【问题标题】:How to call a second-level base class method like base.base.GetHashCode()如何调用像base.base.GetHashCode()这样的二级基类方法
【发布时间】:2009-06-17 11:50:56
【问题描述】:
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

【问题讨论】:

  • 您的意思是让 B 类从 A 类继承吗?
  • @AakashM - 好地方!我在心里插入它,却没有注意到它不存在;我想我们可以假设它应该是......
  • 这在 C# 中是不合法的。是否可以重新设计您的类层次结构,以便派生类型不需要了解其所有基类型的实现细节?

标签: c# inheritance


【解决方案1】:

(编辑 - 误读问题)

如果要获取原版object.GetHashCode();你不能 - 至少,除非A 通过以下方式提供它:

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

(并让B 致电GetBaseHashCode())。

它溢出的原因是GetHashCode (显然)是虚拟的——如果你把它转换成object 也没关系;它仍然从实际对象中派生最多的实现开始,即B.GetHashCode()(因此爆炸)。

【讨论】:

  • 其实我以为你可以用反射来调用一个特定版本的方法,即使它是虚拟的。
  • @LBushkin - 我也这么认为;但是当我不久前尝试它(使用自定义 IL 和“call”而不是“callvirt”)时,CLI 拒绝了它,说它可能会破坏运行时的稳定性(这是一个简单的例子)。
  • 您可以通过创建DynamicMethod 来公然作弊。类似于 Dogett 的 answer to a similar question
  • Try this answer to a similar question: 快,简单,不用碰中级!
【解决方案2】:

可以使用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的原始hashcode:54267293

如果你看一下 Reflector 中的RuntimeHelpers.GetHashCode(object),你会发现它调用了内部静态方法object.InternalGetHashCode(object)。如果您想了解更多信息,请查看 this question 了解 GetHashCode 的默认实现。

【讨论】:

    【解决方案3】:

    我正在使用一个外部库,我也想调用 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();
        }
    

    【讨论】:

    • “相当简单”并不是我在阅读代码时所想的,但它就像一个魅力:-)!
    【解决方案4】:

    如果您可以修改子子类的代码,那么您可以使用静态方法实现子子方法的功能。这个静态(公共)方法的第一个参数是类的对象。这样你就可以从任何地方调用它。

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

    【讨论】:

      猜你喜欢
      • 2015-07-15
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多