Declaring a class to implement an interface is similar to deriving from a base class in that the implemented interfaces appear in a comma-separated list along with the base class (order is not significant). The only difference is that classes can implement multiple interfaces. An example appears in Listing 7.3. Listing 7.3. Implementing an Interface
Once a class declares that it implements an interface, all members of the interface must be implemented. The member implementation may throw a NotImplementedException type exception in the method body, but nonetheless, the method has an implementation from the compiler's perspective. One important characteristic of interfaces is that they can never be instantiated; you cannot use new to create an interface, and therefore, interfaces cannot even have constructors or finalizers. Interface instances are available only from types that implement them. Furthermore, interfaces cannot include static members. One key interface purpose is polymorphism, and polymorphism without an instance of the implementing type is of little value. Each interface member behaves like an abstract method, forcing the derived class to implement the member. Therefore, it is not possible to use the abstract modifier on interface members explicitly. However, there are two variations on implementation: explicit and implicit. Explicit Member ImplementationExplicit members are accessible only when cast to the implemented interface. For example, to call IListable.ColumnValues in Listing 7.4, you must first cast the contact to IListable because of ColumnValues's explicit implementation. Listing 7.4. Calling Explicit Interface Member Implementations
The cast and the call to ColumnValues occur within the same statement in this case. Alternatively, you could assign contact2 to an IListable variable before calling ColumnValues. Declaring an explicit interface member implementation involves prefixing the member name with the interface name (see Listing 7.5). Listing 7.5. Explicit Interface Implementation
Listing 7.5 implements ColumnValues explicitly, for example, because it prefixes the property with IListable. Furthermore, since explicit interface implementations are directly associated with the interface, there is no need to modify them with virtual, override, or public, and, in fact, these modifiers are not allowed. The C# compiler assumes these modifiers; otherwise, the implementation would be meaningless. Implicit Member ImplementationNotice that CompareTo() in Listing 7.5 does not include the IComparable prefix; it is implemented implicitly. With implicit member implementation, it is only necessary for the class member's signature to match the interface members signature. Interface member implementation does not require the override keyword or any indication that this member is tied to the interface. Furthermore, since the member is declared just as any other class member, code that calls implicitly implemented members can do so directly, just as it would any other class member: result = contact1.CompareTo(contact2); In other words, implicit member implementation does not require a cast because the member is not hidden from direct invocation on the implementing class. Many of the modifiers disallowed on an explicit member implementation are required or are optional on an implicit implementation. For example, implicit member implementations must be public. Furthermore, virtual is optional depending on whether derived classes may override the implementation. Eliminating virtual will cause the member to behave as though it is sealed. Interestingly, override is not allowed because the interface declaration of the member does not include implementation, so override is not meaningful. Explicit versus Implicit Interface ImplementationThe key difference between implicit and explicit member interface implementation is obviously not in the method declaration, but in the accessibility from outside the class. Since explicit interface members are hidden without casting to the interface type, they provide a higher degree of encapsulation. Here are several guidelines that will help you choose between an explicit and an implicit implementation.
Much of the decision regarding implicit versus explicit interface member implementation comes down to intuition. However, these questions provide suggestions about what to consider when making your choice. Since changing an implementation from implicit to explicit results in a version-breaking change, it is better to err on the side of defining interfaces explicitly, allowing them to be changed to implicit later on. Furthermore, since the decision between implicit and explicit does not have to be consistent across all interface members, defining some methods as explicit and others as implicit is fully supported. |