programar programacion porque net multilenguaje language ejemplos desde cero aprender c# .net clr bcl

programacion - programar en.net c#



¿Qué hace RuntimeHelpers.GetHashCode? (4)

Creo que la documentación de MSDN está tratando de describir el comportamiento , no la implementación. El punto clave: RuntimeHelpers devuelve la implementación predeterminada que obtendría si fuera object.GetHashCode() no reemplazada.

Esto es realmente útil si, por ejemplo, desea crear una búsqueda de igualdad de referencia , incluso para los tipos que han anulado Equals y GetHashCode . Hago esto en un serializador que mantengo, usando RuntimeHelpers.GetHashCode() y Object.ReferenceEquals .

El RuntimeHelpers.GetHashCode(object) permite generar códigos hash basados ​​en la identidad de un objeto. states MSDN:

El método RuntimeHelpers.GetHashCode siempre llama al método Object.GetHashCode de forma no virtual, incluso si el tipo del objeto ha anulado el método Object.GetHashCode.

[MethodImpl(MethodImplOptions.InternalCall)] [SecuritySafeCritical] public static extern int GetHashCode(object o);

Sin embargo, al inspeccionar el método Object.GetHashCode() usando Reflector (.NET 4.0), veremos el siguiente código:

public virtual int GetHashCode() { return RuntimeHelpers.GetHashCode(this); }

Esto me hace creer que la documentación de MSDN es incorrecta, ya que llamar a Object.GetHashCode desde RuntimeHelpers.GetHashCode(object) causaría un desbordamiento de pila.

Entonces, ¿cuál es el comportamiento real de RuntimeHelpers.GetHashCode(object) y cómo funciona? ¿Cómo se calcula el hash?


De su propia pregunta, parece que RuntimeHelpers.GetHashCode(Object) es realmente la implementación del Object.GetHashCode() no anulado.


El punto es que object.GetHashCode() puede ser anulado, y frecuentemente lo es, por ejemplo, por string . Eso significa que no puede encontrar el "código hash de identidad" que devuelve la implementación predeterminada de object.GetHashCode() .

Esto puede ser útil si desea implementar un comparador de igualdad (por ejemplo, para un HashSet ) que solo considera la identidad del objeto.

Por ejemplo:

public class IdentityComparer<T> : IEqualityComparer<T> where T : class { public bool Equals(T x, T y) { // Just for clarity... return object.ReferenceEquals(x, y); } public int GetHashCode(T x) { // The nullity check may be unnecessary due to a similar check in // RuntimeHelpers.GetHashCode, but it''s not documented return x == null ? 0 : RuntimeHelpers.GetHashCode(x); } }

Entonces:

string x = "hello"; string y = new StringBuilder("h").Append("ello").ToString(); Console.WriteLine(x == y); // True (overloaded ==) Console.WriteLine(x.GetHashCode() == y.GetHashCode()); // True (overridden) IdentityComparer<string> comparer = new IdentityComparer<string>(); Console.WriteLine(comparer.Equals(x, y)); // False - not identity // Very probably false; not absolutely guaranteed (as ever, collisions // are possible) Console.WriteLine(comparer.GetHashCode(x) == comparer.GetHashCode(y));

EDIT: Sólo para aclarar un poco ...

Entonces, ¿cuál es el comportamiento real de RuntimeHelpers.GetHashCode (objeto) y cómo funciona?

El comportamiento observado es que el valor devuelto por RuntimeHelpers.GetHashCode(object) es el mismo que el valor que se devolvería de una llamada no virtual a Object.GetHashCode() . (No puede escribir esa llamada no virtual en C # fácilmente).

En cuanto a cómo funciona , eso es un detalle de la implementación :) En realidad, no importa la OMI en qué forma ocurren las cosas (qué se llama qué). Lo importante es el comportamiento documentado, que es correcto. Demonios, diferentes versiones de mscorlib podrían implementar esto de manera diferente, no importaría en absoluto desde el punto de vista del usuario. Sin la descompilación, no deberías poder notar la diferencia.

Habría sido (IMO) mucho más confuso que Object.GetHashCode hubiera sido documentado en términos de RuntimeHelpers.GetHashCode() .


Extraño, cuando miro System.Object.GetHashCode a través de Reflector veo

public virtual int GetHashCode() { return InternalGetHashCode(this); }

y para runtimehelper:

public static int GetHashCode(object o) { return object.InternalGetHashCode(o); }

Tal vez es una diferencia de marco? Estoy mirando los ensamblajes 2.0.