2009-06-17 4 views
28
class A 
{ 
    public override int GetHashCode() 
    { 
     return 1; 
    } 
} 
class B : A 
{ 
    public override int GetHashCode() 
    { 
     return ((object)this).GetHashCode(); 
    } 
} 

new B().GetHashCode() 

esto desborda la pila. ¿Cómo puedo llamar al Object.GetHashCode() desde B.GetHashCode()?Cómo llamar a un método de clase base de segundo nivel como base.base.GetHashCode()

editar: B ahora hereda de A.

+3

¿Quisiste decir que la clase B hereda de la clase A? – AakashM

+0

@AakashM - ¡buen lugar! Lo inserté mentalmente sin darme cuenta de que no está allí; Creo que podemos suponer que debería ser ... –

+0

debería. lo he agregado – usr

Respuesta

17

(edit - pregunta mala lectura)

Si desea obtener la versión original object.GetHashCode(); no se puede - al menos, no menos que A lo pone a disposición a través de algo como:

protected int GetBaseHashCode() { return base.GetHashCode();} 

(y tienen B llamada GetBaseHashCode()).

La razón por la que se desborda es que GetHashCode es (obviamente) virtual, no importa si lo transfiere a object; todavía comienza en la implementación más derivada en el objeto real, es decir, B.GetHashCode() (de ahí la explosión).

+0

Parece que también lo leí mal. Buena atrapada. – Welbog

+0

En realidad, pensé que puedes usar el reflejo para llamar a una versión específica de un método, incluso si es virtual. – LBushkin

+3

@LBushkin - Yo también pensé eso; pero cuando lo intenté hace un momento (usando IL personalizado y "call" en lugar de "callvirt") el CLI lo rechazó, diciendo que podría desestabilizar el tiempo de ejecución (y eso fue para un ejemplo trivial). –

13

Puede utilizar RuntimeHelpers.GetHashCode(object) para obtener el código hash original del objeto:

class A 
    { 
    public override int GetHashCode() 
    { 
     Console.WriteLine("base hashcode is: " + base.GetHashCode()); 

     return 1; 
    } 
    } 

    class Program 
    { 
    public static void Main(string[] args) 
    { 
     A a = new A(); 

     Console.WriteLine("A's hashcode: " + a.GetHashCode()); 

     Console.WriteLine("A's original hashcode: " + RuntimeHelpers.GetHashCode(a)); 
    } 
    } 

Esto produce el siguiente resultado:

código hash base es: código hash 54267293
de A: 1
El hashcode original de A: 54267293

Si echa un vistazo a RuntimeHelpers.GetHashCode(object) en Reflector, verá que llama al método estático interno object.InternalGetHashCode(object). Si desea obtener más información, consulte this question con respecto a la implementación predeterminada de GetHashCode.

7

Estoy usando una biblioteca externa y quería llamar a base.base también (debido a un error en ciertos casos). Después de algunas investigaciones me encontré con esta página http://www.rsdn.ru/forum/dotnet/475911.aspx

Es muy sencillo: Se define un delegado utilizando la clase base que desea llamar a su método y establecer el puntero de objeto a * esto (o el objeto que desea)

Por lo tanto, el código es importante:

public delegate void MD(); 

public void Test() { 
     // A is the base class you want to call the method. 
     A a = new A(); 
     // Create your delegate using the method name "M" with the instance 'a' of the base class 
     MD am = (MD)Delegate.CreateDelegate(typeof(MD), a, "M"); 
     // Get the target of the delegate and set it to your object (this in most case) 
     am.GetType().BaseType.BaseType.GetField("_target", BindingFlags.Instance BindingFlags.NonPublic).SetValue(am, this); 
     // call the method using the delegate. 
     am(); 
    } 
+0

"bastante simple" no es lo que pensé cuando leí el código, pero funciona como un encanto :-)! –

0

Si se puede modificar el código de la clase sub-sub entonces se puede implementar la funcionalidad de la sub-sub-método con un método estático. Este método estático (público) tiene como primer parámetro un objeto de la clase. De esa manera puedes llamarlo desde cualquier lugar.

class A 
{ 
    public static int CalcHashCode(A obj) 
    { 
     return 1; 
    } 

    public override int GetHashCode() 
    { 
     return CalcHashCode(this); 
    } 
} 
class B : A 
{ 
    public override int GetHashCode() 
    { 
     return A.CalcHashCode(this); 
    } 
} 
Cuestiones relacionadas