显式接口实现,为什么需要显式转换

6
当一个类显式实现一个接口时,为什么需要将类实例显式转换为接口才能使用已实现的方法?
(此示例取自此处:MSDN:显式接口实现
您有两个如下的接口。
interface IControl
{
    void Paint();
}
interface ISurface
{
    void Paint();
}

而且你需要显式地实现它们。

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

现在,要使用接口,您需要以下代码。
// Call the Paint methods from Main.

SampleClass obj = new SampleClass();
//obj.Paint();  // Compiler error.

IControl c = (IControl)obj;
c.Paint();  // Calls IControl.Paint on SampleClass.

ISurface s = (ISurface)obj;
s.Paint(); // Calls ISurface.Paint on SampleClass. 

在上面的代码块中,为什么要有?
IControl c = (IControl)obj;

与...相反
IControl c = obj;

?

我的困惑是因为,例如,您可以执行以下操作。
IDictionary<string, string> c = new Dictionary<string, string>();

不需要显式地将 new Dictionary 强制转换为 IDictionary

谢谢。


1
否则它怎么知道使用哪个隐式实现?它可能是任何一个! - Liam
3
可以,不需要进行转换就可以运行。 - Daniel A. White
@Liam,左边是IControl c,这不够吗? - sakura-bloom
隐式转换没问题。只有在使用隐式类型的局部变量(var关键字)时才需要显式转换;如果在某些地方使用它,可能会导致一些混淆。 - Allan Elder
3
MSDN使用问题描述中的代码IControl c = (IControl)obj;可能会让人感到困惑。为什么他们要对一个隐式转换进行冗余的显式转换?这可能是疏忽导致的错误,也可能是为了更好的可读性。 - P.Brian.Mackey
@P.Brian.Mackey 很好的问题; 我想知道 C# 规范的先前版本是否需要它? - Allan Elder
2个回答

17

当一个类显式实现一个接口时,为什么需要将类实例显式转换为接口才能使用已实现的方法?

对于编译器而言,成员实际上不存在于类中 - 它仅仅存在于接口中。你不必显式地进行类型转换 - 只需拥有一个编译时类型为接口的引用即可。这可以通过任何你喜欢的方式来实现,包括隐式转换。

在上面的代码块中,为什么要这样写:

IControl c = (IControl)obj;

与...相反

IControl c = obj;
您不必这样做,隐式转换应该完全没问题。只有在单个表达式中调用方法时,您才需要明确地进行强制转换,例如:
obj.Paint(); // Invalid
((IControl) obj).Paint(); // Valid

但是,如果你通过将其分配给接口类型的另一个本地变量进行隐式转换,那么这样做就没问题了——方法仍然使用的是接口类型的目标表达式。


那么你的意思是,如果我有一个实现了接口的对象 MyClass o = new MyClass();,并且该接口被显式地实现,那么我不能执行 o.InterfaceMethod();但如果它是 IInterface o = new MyClass();,那么就可以工作。我的理解正确吗? - Mike Perrenoud
1
值得注意的是,在C#中,您可以通过隐式 (http://msdn.microsoft.com/en-us/library/z5z9kes2(v=vs.110).aspx) 和显式 (http://msdn.microsoft.com/en-us/library/xhbhezf4(v=vs.110).aspx) 运算符重载来控制隐式和显式转换。 - Dweeberly

2

仅当一个类型从多个接口继承并且某些方法在多个接口中具有相同的名称/签名时,才需要显式接口实现。

其余的则是个人偏好和约定。

mpleClass obj = new SampleClass();
//obj.Paint();  // Compiler error. 
obj.Paint() --> 这是错误的,因为当进行显式接口实现时,底层接口实现需要按照MSDN中指定的方式进行显式转换。

在方法调用、属性访问或索引器访问中,不能通过其完全限定名称访问显式接口成员实现。显式接口成员实现只能通过接口实例访问,并且在这种情况下,仅通过其成员名称引用。


1
这似乎回答了一个不同的问题 - 即显式接口实现的目的是什么。它并没有回答实际被问到的问题。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接