C#接口的隐式和显式实现之间的区别

Difference between implicit and explicit implementation of C# interfaces

本问题已经有最佳答案,请猛点这里访问。

显式实现接口和实现接口之间的区别是什么?

从接口派生类时,IntelliSense建议您同时执行这两项操作。

但是,有什么区别?


另一方面:

如果隐式实现,则意味着您的类的用户可以访问接口成员,而不必强制转换它。

如果它是显式实现的,那么在能够访问成员之前,客户机必须将类强制转换为接口。下面是一个显式实现的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    interface Animal
{
    void EatRoots();
    void EatLeaves();
}

interface Animal2
{
    void Sleep();
}


class Wombat : Animal, Animal2
{
    // Implicit implementation of Animal2
    public void Sleep()
    {
    }

    // Explicit implementation of Animal
    void Animal.EatRoots()
    {

    }

    void Animal.EatLeaves()
    {
    }

}

您的客户代码

1
2
3
4
Wombat w = new Wombat();
w.Sleep();
w.EatRoots();   // This will cause a compiler error because it's explicitly implemented
((Animal)w).EatRoots();  // This will compile

IDE为您提供了两种选择——这两种选择都不常见。通过显式实现,成员不在(主)公共API上;如果接口与对象的意图没有直接联系,这很方便。例如,ICustomTypeDescriptor成员对常规调用程序并没有太大帮助,只是对一些非常具体的代码有帮助,因此在公共API上使用它们不会造成混乱。

这在以下情况下也很有用:

  • 接口的Foo方法和您自己类型的Foo方法之间存在冲突,它们的含义不同
  • 其他接口之间存在签名冲突

最后一点的典型例子是IEnumerable,它在接口层次结构的两个层次上有一个GetEnumerator()方法-通常使用隐式实现来实现类型化(IEnumerator)版本,使用显式实现来实现非类型化(IEnumerator)版本。


以下是简单英语的区别:

假设您有一个接口Machine,它有一个函数Run(),另一个接口Animal,它也有一个函数Run()。当然,当机器运转时,我们谈论的是它的启动,但当动物运转时,我们谈论的是它在四处移动。所以当你有一个物体,我们称它为Aibo,它既是Machine又是Animal,会发生什么?(顺便问一句,艾博是一只机械狗。)当埃多克斯(EDOCX1)(11)跑的时候,他是启动了,还是四处走动?显式实现接口使您能够做出这样的区分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
interface Animal
{
    void Run();
}
interface Machine
{
    void Run();
}

class Aibo : Animal, Machine
{
    void Animal.Run()
    {
        System.Console.WriteLine("Aibo goes for a run.");
    }
    void Machine.Run()
    {
        System.Console.WriteLine("Aibo starting up.");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Aibo a = new Aibo();
        ((Machine)a).Run();
        ((Animal)a).Run();
    }
}

这里的要点是,我不能简单地调用a.Run(),因为我对函数的两个实现都显式地附加到一个接口上。这是有道理的,否则编译器怎么知道该调用哪一个呢?相反,如果我想在我的Aibo上直接调用Run()函数,我还必须在没有显式接口的情况下实现该函数。


Explicit将放置iInterfaceName。在所有接口实现的前面。如果您需要实现两个包含冲突名称/签名的接口,那么这将非常有用。

更多信息在这里。


显式实现将完全限定名放在函数名上考虑此代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    public interface IamSam
    {
        int foo();
        void bar();
    }

    public class SamExplicit : IamSam
    {
        #region IamSam Members

        int IamSam.foo()
        {
            return 0;
        }

        void IamSam.bar()
        {

        }

        string foo()
        {
            return"";
        }
        #endregion
    }

    public class Sam : IamSam
    {
        #region IamSam Members

        public int foo()
        {
            return 0;
        }

        public void bar()
        {

        }

        #endregion
    }

IamSam var1;
var1.foo()  returns an int.
SamExplicit var2;
var2.foo() returns a string.
(var2 as IamSam).foo() returns an int.

显式接口实现(除非显式强制转换,否则实现是隐藏的)在接口与类功能正交时最有用。也就是说,行为上无关。

例如,如果您的类是Person,并且接口是可ISerializable的,那么对于处理Person属性的人来说,通过IntelliSense看到一些奇怪的称为"GetObjectData"的东西没有多大意义。因此,您可能希望显式实现接口。

另一方面,如果您的Person类恰好实现了IAddress,那么直接在Person实例上看到AddressLine1、ZipCode等成员(隐式实现)是非常有意义的。


区别在于,您可以从几个接口继承一个类。这些接口可能具有相同的方法签名。显式实现允许您根据调用它的接口更改实现。


给你,直接从msdn来