显式或隐式实现接口有什么区别?


64

在Visual Studio中,我可以右键单击一个接口,然后选择“实现接口”或“明确实现接口”。

Visual Studio屏幕截图

public class Test : ITest
{
    public string Id // Generated by Implement Interface
    {
        get { throw new NotImplementedException(); }
    }

    string ITest.Id // Generated by Implement Interface Explicitly
    {
        get { throw new NotImplementedException(); }
    }
}

我看到的两者之间的唯一区别是,如果选择显式实现接口,则在创建接口属性和方法时会将接口名称添加到接口属性和方法中。

我发现它使代码更具可读性,因为我可以看到该方法/属性的来源,但是这对使用或编译该类的方式有什么不同吗?我隐式或显式实现接口真的重要吗?

Answers:


51

请查看安德鲁·巴雷特Andrew Barrett)关于SO的“隐式与显式接口实现” 的最佳答案

基本上:

  • 隐式:访问接口方法和属性,就像它们是类的一部分一样。
  • 明确的:仅在将类视为已实现的接口时才能访问方法和属性。

代码示例:

隐式:

Test t = new Test();
t.Id; // OK
((ITest)t).Id; // OK

显式:

Test t = new Test();
t.Id; // Not OK
((ITest)t).Id; // OK

就“何时”而言,您必须显式实现接口,这是指您的类已经具有与您接口的方法之一具有相同签名的方法,或者当您的类实现了几个共享具有相同签名的方法的接口时但合同不兼容。


1
我还发现显式实现对于具有某种不安全操作的“隐藏”接口很有用。这也使对这些方法的调用更加突出,这对于不安全的事物是一件好事。
陶Szelei

还值得一提的是,使用显式接口会降低性能,因为在您引用属性/方法时,它需要对对象进行装箱/拆箱。因此,最好尽可能使用隐式接口
Rachel

3
@Rachel:据我所知,性能成本仅适用于值类型。
Groky

8

调用方法的方式也有所不同。

使用显式接口实现时,必须使用接口类型才能调用该特定实现。

因此,在调用代码时,您需要使用type变量ITest来访问ITest.Id

MSDN上的“ 显式接口实现”(C#编程指南)一文提供了一个很好的示例。



4

编辑: 不应有所作为 除非您的类实现具有相同属性的两个接口,否则您不应该这样做,因为在访问成员之前,您必须强制转换为相关接口:

public interface ITest
{
    string Id { get; }
}

public interface IAlsoTest
{
    string Id { get; }
}

public interface ITestToo
{
    int Id { get; }
}

public class Test : ITest, IAlsoTest
{
    // Valid implicit implementation of BOTH interfaces
    public string Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestSeparately : ITest, ITestToo
{
    // This way we can do different things depending
    // on which interface the callee called from.
    string ITest.Id
    {
        get { throw new NotImplementedException(); }
    }

    int ITestToo.Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestOuch
{
    public void DoStuff()
    {
        var ts = new TestSeparately();

        // Works
        Console.WriteLine(((ITest)ts).Id);

        // Works
        Console.WriteLine(((ITestToo)ts).Id);

        // Not valid! Which one did we want to call?
        Console.WriteLine(ts.Id);
    }
}

即使您仅使用单个接口(我总是忘记了:S),当您显式实现接口成员时,示例用法仍然适用,因此,我将尽可能避免使用显式实现,因为如果它们隐瞒了类成员,它将隐藏类成员。不要转换为正确的界面(这非常令人困惑)。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.