如何调用第二级基类方法,例如 base.base.GetHashCode()?该问题涉及 IT 技术。

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

new B().GetHashCode()

堆栈溢出。如何从B.GetHashCode()中调用Object.GetHashCode()

编辑:B现在继承自A


3
你的意思是让B类继承A类吗? - AakashM
@AakashM - 发现得好!我在粗心地插入它时没有注意到它不在那里;我想我们可以假设应该是这样... - Marc Gravell
3
在C#中这是不合法的。你是否可以重新设计你的类层次结构,使得派生类型不需要了解其所有基类型的实现细节? - Eric Lippert
4个回答

21
< p >(编辑-误读问题)< / p > < p >如果您想获取原始的< code > object.GetHashCode() < / code >版本;您无法这样做 - 至少除非< code > A 通过类似以下方式使其可用:< / p>
protected int GetBaseHashCode() { return base.GetHashCode();}

(并且让B调用GetBaseHashCode())。

它溢出的原因是GetHashCode是(显然)虚拟的 - 不管你将其转换为object,它仍然从实际对象中最派生的实现开始,即B.GetHashCode()(因此导致了爆炸情况)。


实际上,我认为你可以使用反射调用特定版本的方法,即使它是虚拟的。 - LBushkin
3
@LBushkin - 我也曾这样想,但我前不久尝试了一下(使用自定义 IL 和 "call" 而非 "callvirt"),然而 CLI 拒绝了它,声称它可能会破坏运行时(即便是针对一个微不足道的示例)。 - Marc Gravell
你可以通过创建一个DynamicMethod来明目张胆地作弊。就像Dogett在类似问题的回答中所示。 - Brian
尝试这个类似问题的答案:快速,简单,而且您不需要触及中间类! - Oliver

14
你可以使用RuntimeHelpers.GetHashCode(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));
    }
  }

这会产生以下结果:

基础哈希码为:54267293
A的哈希码:1
A的原始哈希码:54267293

如果你查看Reflector中的RuntimeHelpers.GetHashCode(object),你会看到它调用了内部静态方法object.InternalGetHashCode(object)。如果你想了解更多信息,请查看关于GetHashCode默认实现的这个问题


7
我正在使用外部库,我想调用base.base(因为在某些情况下存在错误)。经过一些研究,我找到了这个页面:http://www.rsdn.ru/forum/dotnet/475911.aspx 很简单:您使用要调用方法的基类定义一个委托,然后将对象指针设置为*this(或您想要的对象)
所以,重要的代码是:
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();
    }

当我读到这段代码时,“相当简单”并不是我的第一反应,但它确实像魔法一样运行良好 :-)! - Jonathan ANTOINE

0
如果您可以修改子子类的代码,那么您可以使用静态方法实现子子方法的功能。这个静态(公共)方法的第一个参数是该类的对象。这样,您就可以从任何地方调用它。
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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接