这将如何运作? (接口和非虚函数)

时间:2009-05-04 22:50:24

标签: c# .net interface

interface I { int J(); }

class A : I
{
   public  int J(){return 0; }  // note NOT virtual (and I can't change this)
}

class B : A, I
{
   new public int J(){return 1; }
}


B b = new B();
A a = b;
I ib = b, ia = a;

b.J(); // should give 1
a.J(); // should give 0 (IMHO)

ia.J(); // ???
ib.J(); // ???

我知道我可以尝试一下,但我正在寻找一个好的权威来源这个角落,我宁愿不仅仅是开始通过MSDN文本进行近视挖掘(我还没有谷歌的一个线索)。

3 个答案:

答案 0 :(得分:2)

重写:由于我们正在谈论实现IDisposable,真正的重要性在于确保Derived和Base类都有机会运行各自的清理代码。这个例子将涵盖场景的2/3;但是因为它派生自Base()而Base.Dispose()不是虚拟的,所以对((Base)Child).Dispose()的调用不会为Child类提供清理的机会。

唯一的解决方法是不从Base派生Child;然而,这被排除了。调用((IDisposable)Child)。Dispose()和Child.Dispose()将允许Child和Base执行清理代码。

class Base : IDisposable
{
    public void Dispose()
    {
        // Base Dispose() logic
    }
}

class Child : Base, IDisposable
{
    // public here ensures that Child.Dispose() doesn't resolve to the public Base.Dispose()
    public new void Dispose()
    {
        try
        {
            // Child Dispose() logic
        }

        finally
        {
            // ensure that the Base.Dispose() is called
            base.Dispose();
        }
    }

    void IDisposable.Dispose()
    {
        // Redirect IDisposable.Dispose() to Child.Dispose()
        Dispose();
    }
}

答案 1 :(得分:1)

您正在与基类或接口提供的合同进行对话并不重要,因为您正在与B类实例交谈,所以它们都会返回1。

答案 2 :(得分:1)

Jeffrey Richter(CLR来自C#): “C#编译器要求将实现接口的方法标记为public。 CLR要求将接口方法标记为虚拟。如果您没有明确标记 在源代码中作为虚拟的方法,编译器将该方法标记为虚拟和 密封;这可以防止派生类重写接口方法。如果你明确 将该方法标记为虚拟,编译器将该方法标记为虚拟(并将其保留为未密封); 这允许派生类重写接口方法“