C#中的接口方法可以显式实现,以便在将实例显式强制转换为接口类型时调用它们的实现。为什么在类的虚方法上也不支持这个?
尽管解决“多重继承”问题对于接口来说是独一无二的,但似乎由于明确实现成员的所有其他原因对接口有用,它们对虚拟方法也很有用。我想到了一个更清晰的返回型协方差模型。
编辑:根据请求,举例:
public class Foo {
...
}
public class Bar : Foo {
...
}
class Base {
abstract Foo A ();
}
class Dervied {
private Bar _b;
Bar A () {
return _b;
}
Foo Base.A () {
return _b;
}
}
我知道使用辅助方法来模拟这个,但是净效果似乎具有显式实现可能具有的任何不良特性,但是使用更脏的API。我的问题的关键不在于如何做返回类型协方差,而是为什么虚拟方法不支持类似的接口机制。
答案 0 :(得分:5)
有些人建议首先不要使用public virtual
方法。而是创建一个表示使用者界面的public
非虚方法,以及一个表示实现者界面的protected virtual
方法。
我不打算将调用者和实施者的合同分开“混淆设计”。在许多情况下,它是更清洁的国际海事组织,但我通常太懒,实际上这样做。
这种设计在返回类型协方差和方法隐藏方面效果更好。
这样做的另一个好处是public
包装器可以添加额外的检查代码,并支持调用者和实现者的不同合同。
我如何模拟返回类型协方差的示例:
public class Base
{
protected virtual Base FooOverride(int i){return new Base();};//FooOverride does not need to duplicate the argument checking
public Base Foo(int i)
{
if(i<0)
throw new ArgumentException("i<0");
return FooOverride(i);
}
}
public class Derived:Base
{
protected override Base FooOverride(int i){return new Derived();};
public new Derived Foo(int i)
{
return (Derived)base.Foo();
}
}
答案 1 :(得分:3)
除了允许这样的东西之外,还有什么好处?
class Base
{
virtual void M() { }
}
class Derived : Base
{
override void M() { }
override void Base.M() { }
}
这有效地将Liskov Substitution Principle违反到C#语言中 - 如果我有一个Base类型的变量,在它上面调用M()可以做完全不同的事情,具体取决于运行时类型是否为Base或衍生。
显式接口实现是不同的。说你有这个:
interface IFoo
{
void DoStuff();
}
interface IBar
{
void DoStuff();
}
class C : IFoo, IBar
{
void IFoo.DoStuff() { }
void IBar.DoStuff() { }
}
这保留了LSP - 如果我有一个碰巧是运行时类型C的IFoo变量,在它上面调用DoStuff()将得到它的IFoo实现。与IBar一样。