【问题标题】:In C#, why do interface implementations have to implement a another version of a method explicitly?在 C# 中,为什么接口实现必须显式实现另一个版本的方法?
【发布时间】:2012-12-07 06:00:00
【问题描述】:

举个例子:

public interface IFoo
{
    IFoo Bar();
}

public class Foo : IFoo
{
    public Foo Bar()
    {
        //...
    }

    IFoo IFoo.Bar() { return Bar(); } //Why is this necessary?
}

为什么 IFoo Bar() 的隐式实现是必要的,即使 Foo 在没有强制转换的情况下转换为 IFoo

【问题讨论】:

  • 你为什么要这样做?您有效地将Foo 的用户与具体实现联系在一起,使单元测试的模拟变得困难,并且通常会增加应用程序中的耦合...
  • 这两种方法几乎是互斥的。两者都有效,但目的不同。你不会在同一个具体类中对同一个接口使用这两种方法(至少不是我能想到的)
  • @SteveCzetty 因此是 OP 的问题;需要显式实现接口的地方。
  • @AaronMcIver 我的意思是,任何引用Foo(而不是IFoo)具体版本的类都将与该特定实现耦合。

标签: c# .net interface explicit-implementation


【解决方案1】:

因为您可能并不总是希望实现接口的方法与具有相同签名的另一个版本的方法的行为方式相同。

您可能还希望类实现接口的方法,但该方法不能从类本身的实例访问。

【讨论】:

    【解决方案2】:

    微软在这个主题上有一个detailed write up,但它归结为多个接口/类的实现,它们具有相同的方法。在这种情况下,隐式不再起作用

    class Test 
    {
        static void Main()
        {
            SampleClass sc = new SampleClass();
            IControl ctrl = (IControl)sc;
            ISurface srfc = (ISurface)sc;
    
            // The following lines all call the same method.
            sc.Paint();
            ctrl.Paint();
            srfc.Paint();
        }
    }
    
    
    interface IControl
    {
        void Paint();
    }
    interface ISurface
    {
        void Paint();
    }
    class SampleClass : IControl, ISurface
    {
        // Both ISurface.Paint and IControl.Paint call this method.  
        public void Paint()
        {
            Console.WriteLine("Paint method in SampleClass");
        }
    }
    
    // Output: 
    // Paint method in SampleClass 
    // Paint method in SampleClass 
    // Paint method in SampleClass
    

    如果我们采用显式方法,我们最终会得到这个。

    public class SampleClass : IControl, ISurface
    {
        void IControl.Paint()
        {
            System.Console.WriteLine("IControl.Paint");
        }
        void ISurface.Paint()
        {
            System.Console.WriteLine("ISurface.Paint");
        }
    }
    

    这一切都归结为在实现的类型发生冲突时提供唯一性。在您的示例中,Foo IFoo

    【讨论】:

    • 是的,但是这里只有一个界面。
    • 这并没有回答关于返回类型的问题。
    • @Matt 稍微调整了措辞,注意只有一个接口在起作用,但该类也实现了该方法签名。
    • @IlyaKogan 注意到 Foo 是 IFoo。
    【解决方案3】:

    你可以这样解决它(有点难看,但要注意强类型):

    public interface IFoo<T> where T : IFoo<T>
    {
        T Bar();
    }
    
    public class Foo : IFoo<Foo>
    {
        public Foo Bar()
        {
            //...
        }
    }
    

    【讨论】:

    • Большое спасибо,תודה רבה!
    • 由于没有非泛型IFoo 接口,因此无法编译。
    【解决方案4】:

    在这种情况下需要它,因为 C# 不支持接口的返回类型协变,所以你的函数

    public Foo Bar()
    {
        //...
    }
    

    不满足IFoo接口,因为Bar方法的返回类型不同。

    由于您还想实现接口,因此您唯一的选择就是明确地这样做,因为您已经在类上定义了 Bar() 方法。

    【讨论】:

    • 是的,但是为什么 C#不允许这样做?
    • @IlyaKogan - 我不知道为什么 C# 不支持返回类型协方差 - 你必须问设计师。 C# 通常更喜欢将事物明确化,因此可能是为了防止接口被意外隐式实现。
    • @IlyaKogan 这可以追溯到关于实施的每个为什么问题;因为他们选择了。
    • @AaronMcIver 通常可以从逻辑上解释实现选择。
    • @IlyaKogan 很多时候,只是他们认为有更重要的事情需要花时间。
    【解决方案5】:

    我建议您将隐式实现保留为受保护而不是公开。

    public class Foo : IFoo
    {
        **protected virtual** Foo Bar()
        {
            //...
        }
    
        IFoo IFoo.Bar() { return Bar(); } 
    }
    

    对于为什么/何时在此线程中使用显式实现有一个相当广泛的答案:

    implicit vs explicit interface implementation

    使用显式实现的一个很好的理由是,当您使用 Foo 类时,您可以轻松地使用依赖注入来获得更松散的耦合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      • 2014-09-16
      • 2019-10-09
      • 1970-01-01
      • 2016-06-16
      • 2011-04-24
      相关资源
      最近更新 更多