29
class A
{
    public override int GetHashCode()
    {
        return 1;
    }
}
class B : A
{
    public override int GetHashCode()
    {
        return ((object)this).GetHashCode();
    }
}

new B().GetHashCode()

this overflows the stack. How can I call Object.GetHashCode() from B.GetHashCode()?

edit: B now inherits from A.

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
usr
  • 168,620
  • 35
  • 240
  • 369
  • 3
    Did you mean to have class B inherit from class A? – AakashM Jun 17 '09 at 11:54
  • @AakashM - good spot! I mentally inserted it without noticing it isn't there; I think we can assume it should be... – Marc Gravell Jun 17 '09 at 11:56
  • 3
    This is not legal in C#. Is it possible to redesign your class hierarchy so that derived types do not need to know about the implementation details of all of their base types? – Eric Lippert Jun 17 '09 at 15:18

4 Answers4

20

(edit - misread question)

If you want to get the original object.GetHashCode() version; you can't - at least, not unless A makes it available via something like:

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

(and have B call GetBaseHashCode()).

The reason it overflows is that GetHashCode is (obviously) virtual - it doesn't matter if you cast it to object; it still starts at the most-derived implementation in the actual object, i.e. B.GetHashCode() (hence the explosion).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Actually, I thought you can use reflection to call a specific version of a method, even if it is virtual. – LBushkin Jun 17 '09 at 13:12
  • 3
    @LBushkin - I thought that too; but when I tried it a little while ago (using custom IL and "call" instead of "callvirt") the CLI rejected it, saying it could destabilise the runtime (and that was for a trivial example). – Marc Gravell Jun 17 '09 at 13:32
  • You could blatantly cheat by creating a `DynamicMethod`. Something like Dogett's [answer to a similar question](http://stackoverflow.com/questions/4357729/use-reflection-to-invoke-a-overrided-base-method/4358250#4358250) – Brian Dec 08 '10 at 15:12
  • [Try this answer to a similar question](http://stackoverflow.com/a/14415506/177710): quick, easy, and you don't need to touch the intermediate class! – Oliver Apr 30 '13 at 23:13
14

You can use RuntimeHelpers.GetHashCode(object) to get the original hash code of the object:

  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));
    }
  }

This produces the following result:

base hashcode is: 54267293
A's hashcode: 1
A's original hashcode: 54267293

If you take a look at RuntimeHelpers.GetHashCode(object) in Reflector, you'll see that it calls the internal static method object.InternalGetHashCode(object). If you'd like to know more, have a look at this question regarding the default implementation of GetHashCode.

Community
  • 1
  • 1
Igal Tabachnik
  • 31,174
  • 15
  • 92
  • 157
7

I'm using an external library and I wanted to call the base.base also (because of a bug in certain case). After some research I came across this page http://www.rsdn.ru/forum/dotnet/475911.aspx

It's quite simple: You define a delegate using the base class you want to call your method and set the object pointer to *this (or the object you want)

So, the important code is:

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();
    }
Sauleil
  • 2,573
  • 1
  • 24
  • 27
0

If you can modify the code of the sub-sub class then you can implement the functionality of the sub-sub-method with a static method. This static (public) method has as first parameter an object of the class. That way you can call it from everywhere.

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);
    }
}
schoetbi
  • 12,009
  • 10
  • 54
  • 72