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文本进行近视挖掘(我还没有谷歌的一个线索)。
答案 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要求将接口方法标记为虚拟。如果您没有明确标记 在源代码中作为虚拟的方法,编译器将该方法标记为虚拟和 密封;这可以防止派生类重写接口方法。如果你明确 将该方法标记为虚拟,编译器将该方法标记为虚拟(并将其保留为未密封); 这允许派生类重写接口方法“