Design Guidelines Update: Implementing Interfaces Privately

Another one hot off the presses... As always you comments
are welcome.

        Consider implementing interface members
privately (explicitly), if the members are intended to be called only through
the interface. This includes mainly members supporting some framework
infrastructure, such as data-binding or serialization. For example,
IList<T>.IsReadOnly is intended to be called only by the data-binding
infrastructure though the IList interface. It is almost never called directly on
List<T>.

public class List<T> : IList<T>
{

   bool IList<T>.IsReadOnly
{

         get { …
}

   }

}

Note: You need to be
very careful when dealing with value types and privately implemented interfaces.
Casting a value type to an interface, which is the only way to call privately
implemented members, causes boxing.

           
Consider implementing interface members
privately to simulate covariance (change type of parameters or/and return value
in “overridden” members). For example, IList implementations often change the
type of the parameters and returned values to create “strongly typed
collections”.

public class StringCollection : IList
{

   public string this[int index]{ …
}

   object IList.this[int index] { …
}

}

           
Avoid implementing interfaces privately
without having a strong reason to do so (see guidelines about infrastructure
interfaces and simulating covariance discussed above). Privately implemented
members can be confusing to developers.

           
Do provide protected method that offers
the same functionality as the privately implemented method if the functionality
is meant to be specialized by derived classes. Otherwise it is impossible for
inheritors of the type to call the base method.

public class List<T> : ISerializable
{

   ...

   void
ISerializable.GetObjectData(

      SerializationInfo info,
StreamingContext context) {

     
GetObjectData();

   }

 

   protected virtual void
GetObjectData(

      SerializationInfo info,
StreamingContext context) {

     
...

   }

}