Interface Implementation

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

 public class Contact : PdaItem, IListable, IComparable {   // ...   #region IComparable Members   /// <summary>   ///    /// </summary>   /// <param name="obj"></param>   /// <returns>   /// Less than zero:      This instance is less than obj.   /// Zero                 This instance is equal to obj.   /// Greater than zero    This instance is greater than obj.   /// </returns> public int CompareTo(object obj)                                    {       int result;       Contact contact = obj as Contact;       if (obj == null)       {           // This instance is greater than obj.           result = 1;       }       else if (obj == null)       {           throw new ArgumentException("obj is not a Contact");       }       else if( Contact.ReferenceEquals(this, obj) )       {           result = 0;       }       else       {           result = LastName.CompareTo(contact.LastName);           if (result == 0)           {               result = FirstName.CompareTo(contact.FirstName);           }       }       return result;   }   #endregion      #region IListable Members string[] IListable.ColumnValues                                   {       get       {           // Use index to simplify swapping the order           int index = 0;           string[] values = new string[4];           values[index++] = FirstName;           values[index++] = LastName;           values[index++] = Phone;           values[index++] = Address;           return values;       }   }   #endregion } 

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 Implementation

Explicit 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

 string[] values; Contact contact1, contact2; // ... // ERROR:  Unable to call ColumnValues() directly //         on a contact. // values = contact1.ColumnValues; // First cast to IListable. values = ((IListable)contact2).ColumnValues;                      // ... 

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

 public class Contact : PdaItem,IListable, IComparable {   // ...   public intCompareTo(object obj)   {       // ...   }   #region IListable Members string[] IListable.ColumnValues                                {       get       {           // Use index to simplify swapping the order           int index = 0;           string[] values = new string[4];           values[index++] = FirstName;           values[index++] = LastName;           values[index++] = Phone;           values[index++] = Address;           return values;       }   }   #endregion } 

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 Implementation

Notice 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 Implementation

The 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.

  • Is the member a core part of the class functionality?

    Consider the ColumnValues property implementation on the Contact class. This member is not an integral part of a Contact type but a peripheral member probably accessed only by the ConsoleListControl class. As such, it doesn't make sense for the member to be immediately visible on a Contact object, cluttering up what could potentially already be a large list of members.

    Alternatively, consider the IFileCompression.Compress() member. Including an implicit Compress() implementation on a ZipCompression class is a perfectly reasonable choice, since Compress() is a core part of the ZipCompression class's behavior, so it should be directly accessible from the ZipCompression class.

  • Is the interface member name appropriate as a class member?

    Consider an ITrace interface with a member called Dump() that writes out a class's data to a trace log. Implementing Dump() implicitly on a Person or truck class would result in confusion as to what operation the method performs. Instead, it is preferable to implement the member explicitly so that only from a data type of ITrace, where the meaning is clearer, can the Dump() method be called. Consider using an explicit implementation if a member's purpose is unclear on the implementing class.

  • Is there already a class member with the same name?

    Explicit interface member implementation will uniquely distinguish a member. Therefore, if there is already a method implementation on a class, a second one can be provided with the same name as long as it is an explicit interface member.

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.

Essential C# 2.0
Essential C# 2.0
ISBN: 0321150775
EAN: 2147483647
Year: 2007
Pages: 185 © 2008-2017.
If you may any questions please contact us: