显示实现和隐式实现接口的区别(Implicit and Explicit Interface Implementations)

来源:互联网 发布:hdmi切换器品牌 知乎 编辑:程序博客网 时间:2024/05/09 11:35

Implicit and Explicit Interface Implementations

Rate This

mhop

13 Dec 2006 2:59 AM

  • 19

As I was putting together a post on IEnumerable andIEnumerator Iwas reminded of the subtleties of implicit and explicit interfaceimplementations. C# does not support multiple inheritance, but a class has theoption of implementing one or more interfaces. One challenge with interfaces isthat they may include methods that have the same signatures as existing classmembers or members of other interfaces. Explicit interface implementations canbe used to disambiguate class and interface methods that would otherwiseconflict. Explicit interfaces can also be used to hide the details of aninterface that the class developer considers private.

Disambiguating Methods

Let's look at an example of method disambiguation. In Listing 1 we havestarted to write a class calledC that implements interfacesI1and I2, each of which defines a methodA().

Listing 1. Class C implements interfaces I1 and I2.

interface I1

{

    void A();

}

 

interface I2

{

    void A();

}

 

class C : I1, I2

{

    public void A()

    {

       Console.WriteLine("C.A()");

    }

}

In this case, A() is a public class member that implicitlyimplements a member of both interfaces. A() can be invokedthrough either interface or through the class itself as follows:

Listing 2. A() can be invoked from I1, I2, or C.

C c = new C();

I1 i1 = (I1)c;

I2 i2 = (I2)c;

 

i1.A();

i2.A();

c.A();

The output from this code is

C.A()

C.A()

C.A()

This works fine if you want A() to do the same thing in bothinterfaces. In most cases, however, methods in different interfaces havedistinct purposes requiring wholly different implementations. This is whereexplicit interface implementations come in handy. To explicitly implement aninterface member, just use its fully qualified name in the declaration. A fullyqualified interface name takes the form

InterfaceName.MemberName

In Listing 3 we add an explicit implementation of I1'sA()method.

Listing 3. Class C explicitly implements I1.A().

class C : I1, I2

{

    public void A()

    {

       Console.WriteLine("C.A()");

    }

 

    void I1.A()

    {

       Console.WriteLine("I1.A()");

    }

}

Now when we run the statements from Listing 2 we get

I1.A()

C.A()

C.A()

When an interface method is explicitly implemented, it is no longervisible as a public member of the class. The only way to access it is throughthe interface. As an example, suppose we deleted the implicitimplementation ofA() as shown in Listing 4:

Listing 4. Class C does not implicitly implement A()

class C : I1, I2

{

    void I1.A()

    {

       Console.WriteLine("I2.A()");

    }

}

In this case we would get a compile error saying that C fails toimplementI2.A(). We could fix this error by changing the first line to

class C : I1

but we'd get another compile error when trying to invoke A() as amember of C:

C c = new C();

c.A();

This time the compiler would report that class C does not contain adefinition for methodA(). We get the error because the explicitimplementation ofI1.A() hides A() from the class. The only wayto callI1.A() now is through C's I1 interface:

C c = new C();

I1 i1 = (I1)c;

i1.A();

Explicit interface implementations are sometimes necessary when classesimplement multiple interfaces with conflicting member definitions. A commonexample involves collection enumerators that implementSystem.Collections.IEnumeratorandSystem.Collections.Generic.IEnumerator. In this case both interfaces specify a get-accessor for theCurrentproperty. To create a class that compiles, at least one of the twoget-accessors must be explicitly implemented.

Hiding Interface Details.

In some cases explicit interface implementation can be useful even whendisambiguation is unnecessary. One example is to use an explicit implementationto hide the details of an interface that the class developer considers private.While the level of privacy is not as great as that afforded by the privatekeyword, it can be useful in some circumstances. Listing 5 shows a commonpattern involvingIDisposable.In this case, the Dispose() method is hidden by explicit implementationbecause the method is really an implementation detail that is notgermane to the users of classMyFile. At the very least, the explicitimplementation keeps the interface members out of the class'Intellisenselist.

Listing 5. Using explicit implementation to hide the details ofIDisposable.

interface IDisposable

{

    void Dispose();

}

 

class MyFile : IDisposable

{

    void IDisposable.Dispose()

    {

        Close();

    }

 

    public voidClose()

    {

        // Dowhat's necessary to close the file

       System.GC.SuppressFinalize(this);

    }

}

You can read more about implicit and explicit interface implementations inthisMSDNTutorial or in Version 1.2 ofthe C# Language Specification.

 

Hope this helps.

 

-Mike Hopcroft

 

 转自 http://bbs.csdn.net/topics/320002324

在MSDN上原文:http://msdn.microsoft.com/en-us/library/ms173157.aspx

如果类实现两个接口,并且这两个接口包含具有相同签名的成员,那么在类中实现该成员将导致两个接口都使用该成员作为它们的实现。例如: 

C#  复制代码 
interface IControl
{
    void Paint();
}
interface ISurface
{
    void Paint();
}
class SampleClass : IControl, ISurface
{
    // Both ISurface.Paint and IControl.Paint call this method.
    public void Paint()
    {
    }
}


 

然而,如果两个接口成员执行不同的函数,那么这可能会导致其中一个接口的实现不正确或两个接口的实现都不正确。可以显式地实现接口成员 -- 即创建一个仅通过该接口调用并且特定于该接口的类成员。这是使用接口名称和一个句点命名该类成员来实现的。例如: 

C#  复制代码 
public class SampleClass : IControl, ISurface
{
    void IControl.Paint()
    {
        System.Console.WriteLine("IControl.Paint");
    }
    void ISurface.Paint()
    {
        System.Console.WriteLine("ISurface.Paint");
    }
}


 

类成员 IControl.Paint 只能通过 IControl 接口使用,ISurface.Paint 只能通过 ISurface 使用。两个方法实现都是分离的,都不可以直接在类中使用。例如: 

C#  复制代码 
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.


 

显式实现还用于解决两个接口分别声明具有相同名称的不同成员(如属性和方法)的情况: 

C#  复制代码 
interface ILeft
{
    int P { get;}
}
interface IRight
{
    int P();
}


 

为了同时实现两个接口,类必须对属性 P 和/或方法 P 使用显式实现以避免编译器错误。例如: 

C#  复制代码 
class Middle : ILeft, IRight
{
    public int P() { return 0; }
    int ILeft.P { get { return 0; } }
}



自己动手试一试的冲动有没有??(~