vuelve porque populares mis los intentarlo hashtags guardaron funcionan cambios aparezco aparecen c# .net delegates hashcode

c# - porque - ¿Por qué 2 instancias delegadas devuelven el mismo código hash?



no se guardaron los cambios vuelve a intentarlo instagram (4)

¡Fácil! Dado que aquí está la implementación de GetHashCode (sentado en el Delegate clase base):

public override int GetHashCode() { return base.GetType().GetHashCode(); }

(sentado en la clase base MulticastDelegate que llamará arriba ):

public sealed override int GetHashCode() { if (this.IsUnmanagedFunctionPtr()) { return ValueType.GetHashCodeOfPtr(base._methodPtr); } object[] objArray = this._invocationList as object[]; if (objArray == null) { return base.GetHashCode(); } int num = 0; for (int i = 0; i < ((int) this._invocationCount); i++) { num = (num * 0x21) + objArray[i].GetHashCode(); } return num; }

Usando herramientas como Reflector, podemos ver el código y parece que la implementación predeterminada es tan extraña como vemos arriba.

El valor de tipo aquí será Action . Por lo tanto, el resultado anterior es correcto .

ACTUALIZAR

Toma lo siguiente:

var x = new Action(() => { Console.Write("") ; }); var y = new Action(() => { }); var a = x.GetHashCode(); var b = y.GetHashCode(); Console.WriteLine(a == b); Console.WriteLine(x == y);

Esto se imprimirá:

True False

¿Por qué el hashcode es el mismo?

Es algo sorprendente, y hará que usar delegados en un Dictionary tan lento como una List (también conocido como O(n) para búsquedas).

Actualizar:

La pregunta es por qué. ¿Quién tomó una decisión tan tonta?

Una mejor implementación de hashcode hubiera sido:

return Method ^ Target == null ? 0 : Target.GetHashcode(); // where Method is IntPtr


Desde MSDN:

La implementación predeterminada de GetHashCode no garantiza unicidad o consistencia; por lo tanto, no debe utilizarse como un identificador de objeto único para fines de hashing. Las clases derivadas deben anular GetHashCode con una implementación que devuelve un código hash único. Para obtener los mejores resultados, el código hash debe basarse en el valor de un campo o propiedad de instancia, en lugar de un campo o propiedad estático.

Entonces, si no ha sobrescrito el método GetHashCode, puede devolver lo mismo. Sospecho que esto se debe a que lo genera a partir de la definición, no de la instancia.


Esto huele a algunos de los casos mencionados en este hilo, tal vez le dará algunos consejos sobre este comportamiento. de lo contrario, podrías registrarlo allí :-)

¿Cuál es el caso de esquina más extraño que has visto en C # o .NET?

Rgds GJ


Mi primer intento de una mejor implementación:

public class DelegateEqualityComparer:IEqualityComparer<Delegate> { public bool Equals(Delegate del1,Delegate del2) { return (del1 != null) && del1.Equals(del2); } public int GetHashCode(Delegate obj) { if(obj==null) return 0; int result = obj.Method.GetHashCode() ^ obj.GetType().GetHashCode(); if(obj.Target != null) result ^= RuntimeHelpers.GetHashCode(obj); return result; } }

La calidad de esto debería ser buena para los delegados de un solo lanzamiento, pero no tanto para los delegados de multidifusión (si recuerdo correctamente, Target / Method devuelve los valores del último elemento delegado).

Pero no estoy realmente seguro de si cumple con el contrato en todos los casos de esquina.

Mmm, parece que la calidad requiere la igualdad referencial de los objetivos.