显式接口实现不能是虚的

本文关键字:不能 显式接口实现 | 更新日期: 2023-09-27 18:05:55

声明一下,我已经见过这个connect项,但我真的不明白支持它会有什么问题。

假设我有以下代码:

public interface IInterface
{
    void Method();
}
public class Base : IInterface
{
    virtual void IInterface.Method()
    {
        throw new NotImplementedException();
    }
}

虚拟标识符有什么问题?使用虚修饰符可以使override表明基类中有不同的实现。我现在可以通过删除虚拟方法并创建派生类使其工作,如下所示:

public class Derived : IInterface
{
    void IInterface.Method()
    {
        throw new NotImplementedException();
    }
}

然而,这样我真的没有任何迹象表明我重写了什么。

更新:
根据c#(第20.4.1部分:显式接口成员实现)规范,有两个原因。

  1. 隐藏某些方法(我正在使用它)。
  2. 有两个签名相同但返回类型不同的函数(例如对IClonable很有用)。

但是它没有说明为什么不能使这些方法为虚方法。

更新2:
鉴于这些答案,我想我应该在这里重新表述真正的问题。以上两个原因是为什么显式实现接口成为可能的首要原因。为什么把方法设为虚方法会有问题呢?

显式接口实现不能是虚的

显式实现接口的方法具有特殊的可见性作用域=除非您将"this"强制转换为目标接口类型,否则您不能从另一个方法访问它。我想这就是为什么不支持虚拟说明符的原因——你不能覆盖不是普通对象接口(私有/受保护/公共)一部分的方法。

这是我的解决方案:

public class Base : IInterface
{    
   protected virtual void Method()
   {
   }
   void IInterface.Method()    
   {        
       this.Method()
   }
 }

 public class Derived : Base
 {
     protected override void Method()
     {
     }
 }

但是这样我就没有任何迹象表明我重写了什么

嗯,你有,在某种程度上——你有一个事实,那就是它显然是一个显式接口实现。这表明它为在接口上指定的方法调用提供了多态行为…为什么基类是否也实现接口很重要?当您阅读代码时,这对您有什么影响?

对我来说,声明override的主要好处是确保我确实获得了正确的签名—它与我试图覆盖的内容相匹配。你已经从显式接口实现中得到了好处,就像你给了一个不存在的方法或错误的参数等,编译器已经抱怨了。

我可以排序理解你的观点,但我从来没有发现这是一个实际的问题。

能够让显式接口实现是虚拟的只在一种情况下有用:当派生类重写需要调用父类实现时。不幸的是,即使显式接口实现可以成为虚的,如果没有一些新的语法,重写类也无法调用父类的实现。VB.net很好地处理了这个问题,它允许一个实现接口的方法被声明为Protected,并使用与接口方法不同的名称。因此,派生类可以覆盖Protected方法(使用适当的名称),并且该覆盖可以调用父类版本(使用相同的名称)。

如果只有一个接口被继承,为什么你需要这样做:

public class Base : IInterface
{
    virtual void IInterface.Method()
    {
       throw new NotImplementedException();
    }
}

为什么不直接去呢:

public class Base : IInterface
{
   virtual void Method()
   {
      throw new NotImplementedException();
   }
}

我认为原因可以简单地用下面的例子来说明。考虑以下代码:

public interface IInterfaceA
{
    void Method();
}
public interface IInterfaceB
{
    void Method();
}
public class Base : IInterfaceA, IInterfaceB
{
    virtual void IInterfaceA.Method()
    {
       ...
    }
    virtual void IInterfaceB.Method()
    {
       ...
    }
}
public class Derived : Base
{
    public override void Method()
    {
        // Will this override IInterfaceA or IInterfaceB implementation???
    }
}

所以,简而言之,如果你显式地用相同的方法签名实现多个接口,你的派生类将不知道你想要覆盖哪个基方法。