在没有警告的情况下隐藏基类的显式接口实现的目的是什么?

时间:2017-06-23 11:55:02

标签: c# interface polymorphism

想象一下这些规范来自外部dll。一个明确实现接口的类:

public interface IDebug
{
    string GetImportantInfo();
}
public class ExternalClass : IDebug
{
    public void DoSomethingImportant()
    {
        System.Diagnostics.Debug.WriteLine("Something important was done...");
    }
    string IDebug.GetImportantInfo() //Explicit implementation
    {
        DoSomethingImportant();
        return nameof(ExternalClass);
    }
}

然后这个来自内部代码,您知道需要实现该接口:

public class Debug : ExternalClass, IDebug
{
    public string GetImportantInfo()
    {
        return nameof(Debug);
    }
}

现在,当我从子类调用Debug的{​​{1}}方法时,不会调用超类中的显式实现:

GetImportantInfo()

我似乎得到的唯一一个小提示是,在static void Main(string[] args) { IDebug test = new Debug(); var impInfo = test.GetImportantInfo(); System.Diagnostics.Debug.WriteLine(impInfo); //"Debug" } 类添加IDebug接口时,我没有遇到编译错误,而没有实现该方法:

Debug

为什么在覆盖超类的实现时没有编译警告?如果基类隐式实现它,我会收到编译警告,告诉我使用public class Debug : ExternalClass, IDebug { } 关键字。但是使用new关键字覆盖显式实现的方法会产生编译警告:

  

成员'Program.Debug.GetImportantInfo()'不会隐藏继承的成员。新关键字不是必需的。

这是否有预期目的,或者这是一个错误?如果有意,官方推理是什么?

2 个答案:

答案 0 :(得分:1)

这里的问题是您使用的语言鲜为人知:界面重新实现

public class Debug : ExternalClass, IDebug
{
    public string GetImportantInfo()
    {
        return nameof(Debug);
    }
}

如果Debug已经执行,为什么要重新声明IDebug实施ExternalClass?你正在重新实现界面,因为你正在做这样的事情,你没有得到任何警告;编译器假定您知道自己在做什么。

如果您想要您想要的行为,只需不要重新实现界面

public class Debug : ExternalClass
{
    public string GetImportantInfo()
    {
        return nameof(Debug);
    }
}
  

如果基类隐式实现它,我会收到一个编译警告,告诉我使用new关键字。

此警告与接口实现无关。警告只是由于方法隐藏,你有两个方法具有相同的签名; IDebug在这里是一个非因素,你可以把它排除在等式之外,你仍会得到同样的警告。

  

在我的同事的情况下,他说他必须实现基类和接口,因为它是一个基于事件的界面。

那么,告诉你的同事找出他想要的东西。如果您重新实现界面,则对DoSomething的任何调用(通过Debug类型引用或IDebug类型引用)都应调用重新实现的行为。任何其他行为都会出乎意料并且令人深感困惑。

另一方面,如果您需要通过DoSomething()类型引用调用IDebug来保持基类的原始行为,那么不会重新实现接口。你还提出了另外一种选择吗?

这是否意味着您应该了解基类实现的接口?嗯,是的,当然。我发现你的问题是为什么任何人都应该知道你要从实现中继承的任何给定类的接口,实在是非常令人担忧。

答案 1 :(得分:0)

如果使用Explicit实现,则在没有强制转换为接口的情况下,在类中看不到方法。 你将无法致电

new ExternalClass().GetImportantInfo()

但你可以打电话

((IDebug)new ExternalClass()).GetImportantInfo();

由于显式实现,新关键字不是必需的。您甚至可以在一个类中添加两个实现:

    public class ExternalClass : IDebug
    {
        string IDebug.GetImportantInfo() //Explicit implementation
        {
            return "Explicit";
        }
        public string GetImportantInfo() 
        {
            return nameof(ExternalClass);
        }
    }

此外,您的Debug类不必继承IDebug接口,因为它继承了ExternalClass。 Resharper会告诉你这是多余的。