【问题标题】:Explicit interface implementation cannot be virtual显式接口实现不能是虚拟的
【发布时间】:2011-10-28 17:47:10
【问题描述】:

为了记录,我已经看到了这个connect item,但我真的不明白支持这个会有什么问题。

假设我有以下代码:

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. 有 2 个具有相同签名但返回类型不同的函数 (例如对 IClonable 很有用)。

它没有说明为什么不能将这些方法设为虚拟。

更新 2:
鉴于答案,我认为我应该在这里重新表述真正的问题。如果上述两个原因是首先使接口的显式实现成为可能的原因。如果您将方法设为虚拟,为什么会有问题。

【问题讨论】:

    标签: c# compiler-construction interface explicit-interface


    【解决方案1】:

    实现接口的方法显式具有特殊的可见性范围 = 除非您将“this”强制转换为目标接口类型,否则您无法从其他方法访问它。我想这是不支持虚拟说明符的原因 - 您不能覆盖不属于普通对象接口(私有/受保护/公共)的方法。

    这是我的解决方法:

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

    【讨论】:

    • 我不想在基本类型上使用该方法。这样,它在不属于 IInterface 类型的实例中变得可见。显式实现的一个好处是在不通过接口访问类时隐藏方法。
    • 如果它被声明为“受保护”,只有派生类才能看到它。所以你有私有接口实现和派生类的可扩展性
    • 所有从“Base”派生的类都是IInterface类型,只能替换实现。
    • 在这种情况下使用的方法与 Albahari 的 C# 5.0 in a Nutshell 建议的方法完全相同。
    • 这应该是迄今为止该问题的最佳答案。将方法更改为“受保护的虚拟 void InnerMethod()”可能是一个更好的名称。
    【解决方案2】:

    但是这种方式我真的没有任何迹象表明我正在覆盖某些东西

    嗯,你确实这样做了——你知道它显然是一个显式的接口实现。这表明它为在接口上指定的方法调用提供了多态行为......为什么基类 是否实现了接口很重要?阅读代码对你有什么影响?

    对我来说,声明override 的主要好处是确保我真的得到了正确的签名——它与我想要覆盖的东西相匹配。您已经通过显式接口实现获得了这种好处,就好像您提供了一个不存在的方法或错误的参数等,编译器已经抱怨了。

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

    【讨论】:

    • 对我来说,它还告诉我我可能会从基类中替换(如果我不调用基本实现)功能。我的主要“问题”是(对我来说)覆盖普通方法并且无法为显式实现做同样的事情是很尴尬的。我希望这将以相同的方式实现。
    • @thekip:基本上,显式接口实现在很多方面都很奇怪。我会坚持使用隐式接口实现,除非你真的需要使用显式接口实现,或者除非你试图主动隐藏一个不应该被调用的方法根本 (例如,不可变类型的变异方法)。请记住,使用显式接口实现,您的派生类方法甚至不能先调用基类方法。
    • 好吧,当我在派生类中重写显式接口方法时,我知道我的基类也实现了相同的接口,因此我可以安全地将我的基类转换为IInterface 并调用基类方法. C# 规范给出了明确实现可用的 2 个原因(请参阅问题),但我看不出虚拟部分无效的原因。
    • @thekip:“将我的基础转换为 IInterface”是什么意思?你所拥有的只是“this”,如果你将 that 引用投射到IInterface,你最终会再次调用自己。 (如果你有调用基本实现的方法,我很想看看。)
    • 没关系,我看到这是实现显式接口时的另一个限制。这可能就是为什么也不需要重写(因此指定虚拟)的原因,因为您不能真正重写一个函数,而只是完全替换它。
    【解决方案3】:

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

    【讨论】:

    • 在我看来你是说显式接口实现不能是virtual 因为它不能是override :-p。如果我使用显式接口实现的唯一原因是为了避免当前类中的命名空间冲突,我觉得它支持virtualoverride 就像普通方法一样自然。所以我猜VB方法听起来不错……
    • @binki:恕我直言,VB 方法是 .NET 工作方式的“正确”方法之一。它允许解决命名空间冲突问题,允许子方法正确链接到其父方法,而无需创建其唯一目的只是调用虚拟方法的接口实现。如果 .NET 允许一个类型覆盖和隐藏一个方法,或者允许私有虚函数(可以被覆盖,但只能链接到从派生实现中),其他一些方法可能是也不错。
    【解决方案4】:

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

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

    为什么不去:

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

    【讨论】:

    • 可能只是他向我们展示的样本。如果假设可能有另一个以 Method() 作为名称的自定义方法。
    • 因为方法只在接口的上下文中相关。不处理接口实例时无需调用该方法。
    【解决方案5】:

    我认为原因可以在以下示例中简单说明。考虑这段代码:

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

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

    【讨论】:

    • 那么 - 覆盖 void IInterfaceA.Method() ..?这样就可以了。顺便提一句。您不能在显式接口实现上指定 public。默认是公开的。
    • 这个答案似乎只是说“它不能完成,因为它没有语法”。我们问为什么没有支持(包括消除override/base引用的语法),而不是重述(我认为)。
    猜你喜欢
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2011-05-24
    • 2011-03-21
    • 2012-06-15
    • 2010-11-18
    • 1970-01-01
    相关资源
    最近更新 更多