C# 为什么是显式接口实现?

C# 为什么是显式接口实现?,c#,interface,C#,Interface,我最近实现了一个类,如: class TestClass : IDisposable { RegistryKey m_key; public TestClass() { m_key = Registry.CurrentUser.OpenSubKey("Software", false); } public void Dispose() { // m_key.Dispose(); IDisposabl

我最近实现了一个类,如:

class TestClass : IDisposable
{
    RegistryKey m_key;
    public TestClass()
    {
        m_key = Registry.CurrentUser.OpenSubKey("Software", false);
    }

    public void Dispose()
    {
        // m_key.Dispose();
        IDisposable disp = m_key;
        disp.Dispose();
    }
}
如果取消对Dispose的直接调用的注释,则会出现错误CS0117(“Microsoft.Win32.RegistryKey”不包含“Dispose”的定义)。谷歌搜索把我带到了那里,在那里我知道了发生了什么,所以我现在明白了它的机理。文档表明作者希望我调用Close()而不是Dispose(),但没有解释原因

这种模式的目的是什么(我想我在IO类中也看到过这种模式)?鉴于这是类作者有意做出的决定,上面的代码(通过IDisposable接口调用Dispose)有多糟糕?这不会太糟糕——毕竟,这是using语句中会发生的事情,对吗


[编辑:1)将标题从“非公开”更改为“显式”2)从我的代码中删除了显式实现,这是实验中意外留下的]

这称为显式接口实现。在您的示例中,由于您将Dispose()方法定义为“void IDisposable.Dispose()”,因此也显式实现了IDisposable接口

这通常是为了避免碰撞。如果Microsoft想要添加另一个Dispose()方法,该方法对RegistryKey执行了其他操作,则除非使用该接口的显式实现,否则他们将无法添加该方法

这通常通过通用IEnumerable接口完成。它还要求您实现非泛型接口IEnumerable。这两个接口中唯一的成员是GetEnumerator,通用的成员更有用,因此其实现方式通常如下:

public clas SomeClass : IEnumerable<SomeOtherClass>
{
    public IEnumerator<SomeOtherClass> GetEnumerator ()
    {
        ...
    }

    IEnumerator IEnumerable.GetEnumerator ()
    {
        return GetEnumerator ();
    }
}
public类SomeClass:IEnumerable
{
公共IEnumerator GetEnumerator()
{
...
}
IEnumerator IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
}
这样,当您调用SomeClass的GetEnumator方法的对象时,它会调用泛型版本,因为另一个是显式实现的,允许我们获得泛型允许的强类型


参见Jesse Liberty编写的《编程C》第166-169页(我有第四版)。

大多数人不同意我的观点,但我喜欢对所有接口使用显式接口实现。我想弄清楚我是在写一个在我的对象上调用的方法,还是在我的接口上调用的方法

如果您有一个对对象的引用,并且想要调用接口方法(如上面的示例),那么这是很痛苦的,但是我通过编写以下代码来减轻这种痛苦:

class C : IDisposable
{
    public IDisposable IDisposable { get { return this; } }
    void IDisposable.Dispose() { }
}
这意味着在C上调用该方法如下所示:

C c = ...
c.IDisposable.Dispose();
编译器将其解析为“在C上调用
IDisposable
属性,然后在结果上调用
Dispose()
方法”,但我将其理解为“在
C
上调用
IDisposable.Dispose()
方法”,这在这里似乎很自然


不幸的是,当使用通用接口时,这种方法可能会变得丑陋

在显式接口上也是如此。泛型有时会使它变得非常困难。Eek-使用显式接口实现不仅会使调用方在没有上述解决方法的情况下变得更加困难,而且还会破坏继承-如果派生类想要重写接口方法,那么您会遇到棘手的情况。我尽量避免。这个建议构成了糟糕的编程实践。类实现接口是因为它是该接口的实例。作者关于需要显式强制转换的论点同样适用于从父类继承的所有方法——除非强制转换到父类类型,否则不应该调用父方法。这会很奇怪——继承的要点是这个类就是那个父类。父类和接口之间的区别是技术上的区别,以避免继承树中出现菱形,而不是语义上的菱形。不要升级@Qudeid:首先,当试图覆盖子类中的实现时,这会成为一件痛苦的事情(如前所述)。虽然您经常希望将调用者与特定实现分离,但有时他们确实需要该实现,这是有充分理由的。。。在这一点上,你让他们的生活更加艰难。“从接口删除方法”是一个有趣的观点,但是考虑到您必须首先删除接口方法的所有调用方,删除实现也不是那么多工作。我大部分时间都会坚持隐式实现。@JonSkeet我就是这么做的,但考虑到在我的新工作中看到显式实现的过度使用,这真的让我很震惊,即使是将其转换到接口以使用成员,我在互联网上查找更多信息,找到将显式实现作为默认值的codeproject页面,该页面带有诸如从接口中删除方法之类的参数。现在,如果您需要继承,那么您有一个受保护的虚拟方法,该方法将在显式实现中被调用,现在您回到原点,因为编译器没有告诉您关于该方法的任何信息。非常感谢。您可以使用
(m_键作为IDisposable).Dispose()用于速记。