为什么';tc#支持显式实现的虚拟方法吗?

为什么';tc#支持显式实现的虚拟方法吗?,c#,interface,virtual-functions,explicit-implementation,C#,Interface,Virtual Functions,Explicit Implementation,C#中的接口方法可以显式实现,因此当实例显式转换为接口类型时,会调用它们的实现。为什么类的虚拟方法也不支持这一点 尽管解决“多重继承”问题对于接口来说是独一无二的,但似乎出于其他原因,显式实现的成员对于接口很有用,对于虚拟方法也很有用。脑海中浮现出一个更清晰的回归型协方差模型 编辑:根据请求,例如: public class Foo { ... } public class Bar : Foo { ... } class Base { abstract Foo A ();

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

我知道使用helper方法来模拟这一点,但是净效果似乎具有显式实现所具有的任何不良特性,但是使用了更脏的API。我的问题的关键不是如何做返回类型协方差,而是为什么虚拟方法不支持类似的接口机制。

除了允许这样做之外,还有什么好处

class Base
{
    virtual void M() { }
}

class Derived : Base
{
    override void M() { }

    override void Base.M() { }
}
这有效地将违反写入了C#语言中——如果我有一个Base类型的变量,那么根据运行时类型是Base还是派生类型,对它调用M()可以做完全不同的事情


显式接口实现是不同的。假设你有这个:

interface IFoo
{
    void DoStuff();   
}

interface IBar
{
    void DoStuff();
}

class C : IFoo, IBar
{
    void IFoo.DoStuff() { }

    void IBar.DoStuff() { }
}

这保留了LSP——如果我有一个IFoo变量恰好是运行时类型C,那么对它调用DoStuff()将得到它的IFoo实现。IBar也是如此。

一些人建议首先不要使用
公共虚拟方法。而是创建一个表示使用者接口的
public
非虚拟方法和一个表示实现者接口的
protectedvirtual
方法

我不会把为调用方和实现方分离契约称为“搅乱设计”。在很多情况下,我觉得这样做更干净,但我通常太懒了,不愿意这样做

这种设计在使用返回类型协方差和方法隐藏时效果更好

这样做的另一个好处是,
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();
    }
}
公共类基
{
受保护的虚拟基FooOverride(int i){return new Base();};//FooOverride不需要重复参数检查
公共基地办事处(国际一)
{

if(iOne)公共模式是返回类型协方差,如OP所述。您添加了一个新方法,该方法与
virtual
函数等效,只是它返回了一个更具体的类型。显式实现可用于支持返回类型协方差,而不会使API与隐藏的虚拟助手方法混淆(通过使主基和重写不相关,以显式实现相同的方式破坏主接口)。有趣的是,返回类型协方差是您的链接提到的要求之一,但本机不支持。假设我有一个抽象基类ReadableFoo,带有一个抽象只读属性栏。我想有一个从ReadableFoo派生的类MutableFoo,带有一个读写属性栏。有没有办法创建这样的类不必添加额外的继承层,其目的是覆盖只读属性“Bar”?就此而言,是否有任何方法可以构建一个公开ReadableFoo和MutableFoo(如上所述)的项目,而不公开任何其他类?请注意,ReadableFoo和MutableFoo完全遵守LSP。@supercat:让MutableFoo从ReadableFoo继承对我来说似乎很奇怪。这感觉像是对继承的滥用(但你绝对正确,它不会破坏LSP)。我想我应该做的是让ReadOnlyFoo持有对MutableFoo的
私有readonly
引用,并将所有属性访问委托给该实例。是的,无论何时添加/删除/更改属性,都必须在两个位置进行更新,但使用继承也会遇到同样的问题。我还将看看为什么需要这样做成为一个ReadOnlyFoo和一个易变的Foo——这看起来像是一种代码味道。@Zack Elan:拥有这两个ReadableFoo(而不是ReadOnlyFoo!)的原因ImmutableFoo是指一些例程希望接受一个可以从现在开始读取的Foo,但不关心它以后是否会更改。其他例程可能想要一个他们知道永远不会更改的Foo。可以在ReadableFoo中具体实现只读属性,但前提是所有派生类都希望这样做将它们的信息存储在相同的支持字段中——这一假设可能适用于某些类,但并非所有类。作为一个简单的例子……您能否解释一下您对这一工作的设想?如果
派生
扩展
,您正在寻找一个仅在
Deriv的实现中调用的
Base
上的虚拟方法ed
转换为
Bar
?我看不到这种信息隐藏形式的实用程序。举个例子会有所帮助。显式接口实现是一个bandaid。您必须使用它来解决继承多个接口所带来的歧义,这些接口可能具有相同签名的成员。这是标准问题多重继承的em,减去必须在多个继承实现之间进行选择的问题。这是C#中不存在的问题,因为接口无法定义实现。因此不需要显式方法重写,只有一个基本实现可供选择。您的示例使用
抽象
方法,而不是
virtual
one.你能更准确地回答你的问题吗?抽象方法是虚拟的,更接近于接口中定义的成员,这是我的比较。我的问题旨在涵盖这两种情况。这是一个非常有用的设计。我希望.NET在他们的一些