Explicit Interface Implementation
if a class inherits from 2 or more interfaces and if the interfaces
happen to have the same method names, the class doesn't know which
interface method is being implemented if you use implicit interface
implementation. This is one of the scenarios when you would explicitly
implement an interface.
Implicit Interface Implementtationpublic class MyClass : InterfaceOne, InterfaceTwo
{
public void InterfaceMethod()
{
Console.WriteLine("Which interface method is this?");
}
}
interface InterfaceOne
{
void InterfaceMethod();
}
interface InterfaceTwo
{
void InterfaceMethod();
}
Explicit Interface Implementationpublic class MyClass : InterfaceOne, InterfaceTwo
{
void InterfaceOne.InterfaceMethod()
{
Console.WriteLine("Which interface method is this?");
}
void InterfaceTwo.InterfaceMethod()
{
Console.WriteLine("Which interface method is this?");
}
}
interface InterfaceOne
{
void InterfaceMethod();
}
interface InterfaceTwo
{
void InterfaceMethod();
}
Visual Studio .NET 2003
A class that implements an interface can explicitly implement a member of that interface. When a member is explicitly implemented, it cannot be accessed through a class instance, but only through an instance of the interface. This tutorial contains two examples. The first example illustrates how to explicitly implement and access interface members. The second example shows how to implement two interfaces that have the same member names.
Example 1
This example declares an interfaceIDimensions
, and a class Box
, which explicitly implements the interface members Length
and Width
. The members are accessed through the interface instance myDimensions
.// explicit1.cs interface IDimensions { float Length(); float Width(); } class Box : IDimensions { float lengthInches; float widthInches; public Box(float length, float width) { lengthInches = length; widthInches = width; } // Explicit interface member implementation: float IDimensions.Length() { return lengthInches; } // Explicit interface member implementation: float IDimensions.Width() { return widthInches; } public static void Main() { // Declare a class instance "myBox": Box myBox = new Box(30.0f, 20.0f); // Declare an interface instance "myDimensions": IDimensions myDimensions = (IDimensions) myBox; // Print out the dimensions of the box: /* The following commented lines would produce compilation errors because they try to access an explicitly implemented interface member from a class instance: */ //System.Console.WriteLine("Length: {0}", myBox.Length()); //System.Console.WriteLine("Width: {0}", myBox.Width()); /* Print out the dimensions of the box by calling the methods from an instance of the interface: */ System.Console.WriteLine("Length: {0}", myDimensions.Length()); System.Console.WriteLine("Width: {0}", myDimensions.Width()); } }
Output
Length: 30 Width: 20
Code Discussion
- Notice that
the following lines, in the Main method, are commented out because they
would produce compilation errors. An interface member that is explicitly
implemented cannot be accessed from a class instance:
//System.Console.WriteLine("Length: {0}", myBox.Length()); //System.Console.WriteLine("Width: {0}", myBox.Width());
- Notice also that the following lines, in the Main method,
successfully print out the dimensions of the box because the methods are
being called from an instance of the interface:
System.Console.WriteLine("Length: {0}", myDimensions.Length()); System.Console.WriteLine("Width: {0}", myDimensions.Width());
Example 2
Explicit interface implementation also allows the programmer to inherit two interfaces that share the same member names and give each interface member a separate implementation. This example displays the dimensions of a box in both metric and English units. TheBox
class inherits two interfaces IEnglishDimensions
and IMetricDimensions
, which represent the different measurement systems. Both interfaces have identical member names, Length
and Width
.// explicit2.cs // Declare the English units interface: interface IEnglishDimensions { float Length(); float Width(); } // Declare the metric units interface: interface IMetricDimensions { float Length(); float Width(); } // Declare the "Box" class that implements the two interfaces: // IEnglishDimensions and IMetricDimensions: class Box : IEnglishDimensions, IMetricDimensions { float lengthInches; float widthInches; public Box(float length, float width) { lengthInches = length; widthInches = width; } // Explicitly implement the members of IEnglishDimensions: float IEnglishDimensions.Length() { return lengthInches; } float IEnglishDimensions.Width() { return widthInches; } // Explicitly implement the members of IMetricDimensions: float IMetricDimensions.Length() { return lengthInches * 2.54f; } float IMetricDimensions.Width() { return widthInches * 2.54f; } public static void Main() { // Declare a class instance "myBox": Box myBox = new Box(30.0f, 20.0f); // Declare an instance of the English units interface: IEnglishDimensions eDimensions = (IEnglishDimensions) myBox; // Declare an instance of the metric units interface: IMetricDimensions mDimensions = (IMetricDimensions) myBox; // Print dimensions in English units: System.Console.WriteLine("Length(in): {0}", eDimensions.Length()); System.Console.WriteLine("Width (in): {0}", eDimensions.Width()); // Print dimensions in metric units: System.Console.WriteLine("Length(cm): {0}", mDimensions.Length()); System.Console.WriteLine("Width (cm): {0}", mDimensions.Width()); } }
Output
Length(in): 30 Width (in): 20 Length(cm): 76.2 Width (cm): 50.8
Code Discussion
If you want to make the default measurements in English units, implement the methods
Length
and Width
normally, and explicitly implement the Length
and Width
methods from the IMetricDimensions
interface:// Normal implementation: public float Length() { return lengthInches; } public float Width() { return widthInches; } // Explicit implementation: float IMetricDimensions.Length() { return lengthInches * 2.54f; } float IMetricDimensions.Width() { return widthInches * 2.54f; }
System.Console.WriteLine("Length(in): {0}", myBox.Length()); System.Console.WriteLine("Width (in): {0}", myBox.Width()); System.Console.WriteLine("Length(cm): {0}", mDimensions.Length()); System.Console.WriteLine("Width (cm): {0}", mDimensions.Width());
Implicit and Explicit Interface Implementations
As I was putting together a post on IEnumerable and IEnumerator I
was reminded of the subtleties of implicit and explicit interface
implementations. C# does not support multiple inheritance, but a class
has the option of implementing one or more interfaces. One challenge
with interfaces is that they may include methods that have the same
signatures as existing class members or members of other interfaces.
Explicit interface implementations can be used to disambiguate class and
interface methods that would otherwise conflict. Explicit interfaces
can also be used to hide the details of an interface that the class
developer considers private.
Disambiguating Methods
Let's look at an example of method disambiguation. In Listing 1 we have started to write a class called C that implements interfaces I1 and I2, each of which defines a method A().
Listing 1. Class C implements interfaces I1 and I2.
Listing 2. A() can be invoked from I1, I2, or C.
Listing 3. Class C explicitly implements I1.A().
Listing 4. Class C does not implicitly implement A()
Hiding Interface Details.
In some cases explicit interface implementation can be useful even when disambiguation is unnecessary. One example is to use an explicit implementation to 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 private keyword, it can be useful in some circumstances. Listing 5 shows a common pattern involving IDisposable. In this case, the Dispose() method is hidden by explicit implementation because the method is really an implementation detail that is not germane to the users of class MyFile. At the very least, the explicit implementation keeps the interface members out of the class' Intellisense list.
Listing 5. Using explicit implementation to hide the details of IDisposable.
Disambiguating Methods
Let's look at an example of method disambiguation. In Listing 1 we have started to write a class called C that implements interfaces I1 and I2, each of which defines a method A().
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 implicitly implements a member of both interfaces. A() can be invoked through 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 isC.A() C.A() C.A()This works fine if you want A() to do the same thing in both interfaces. In most cases, however, methods in different interfaces have distinct purposes requiring wholly different implementations. This is where explicit interface implementations come in handy. To explicitly implement an interface member, just use its fully qualified name in the declaration. A fully qualified interface name takes the form
InterfaceName.MemberNameIn Listing 3 we add an explicit implementation of I1's A() 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 longer visible as a public member of the class. The only way to access it is through the interface. As an example, suppose we deleted the implicit implementation of A() 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 to implement I2.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 a member of C:C c = new C();
c.A();
This time the compiler would report that class C does not contain a definition for method A(). We get the error because the explicit implementation of I1.A() hides A() from the class. The only way to call I1.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
classes implement multiple interfaces with conflicting member
definitions. A common example involves collection enumerators that
implement System.Collections.IEnumerator and System.Collections.Generic.IEnumerator. In this case both interfaces specify a get-accessor for the Current property. To create a class that compiles, at least one of the two get-accessors must be explicitly implemented.Hiding Interface Details.
In some cases explicit interface implementation can be useful even when disambiguation is unnecessary. One example is to use an explicit implementation to 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 private keyword, it can be useful in some circumstances. Listing 5 shows a common pattern involving IDisposable. In this case, the Dispose() method is hidden by explicit implementation because the method is really an implementation detail that is not germane to the users of class MyFile. At the very least, the explicit implementation keeps the interface members out of the class' Intellisense list.
Listing 5. Using explicit implementation to hide the details of IDisposable.
interface IDisposable { void Dispose(); } class MyFile : IDisposable { void IDisposable.Dispose() { Close(); } public void Close() { // Do what's necessary to close the file System.GC.SuppressFinalize(this); } }
No comments:
Post a Comment