Design Guideline Update: Explicit Member Implementation

Long overdue update the the guidelines on Explicit member implementation.
As always, feedback welcome.


Explicit
Member  Implementation

Explicit member implementation allows an interface member to be implemented
such that it is only available when cast to the interface type.  For example consider the following
definition:

public struct Int32 : IConvertible, IComparable
{
public override string
ToString () {..}
int
ICovertible.ToInt32 () {..}

...
}

This code calls the IConvertable members:

int i = 42;
i.ToString(); // works
i.ToInt32(); // does not
compile
((IConvertible) i).ToInt32();
// works

           
Do not use explicit
members as a security boundary. They can be called by any client who cast an
instance to the interface.

*
Do use explicit
members to hide implementation details

*
Do use explicit members to
approximate private interface implementations. If you need to implement an interface
for only infrastructure reasons and you NEVER expect developers to directly call
methods on that interface from this type then implement the members explicitly
to “hide” them from public view.
For example, all of the base datatypes must
implement IConvertable for infrastructure reasons. IConvertable has 19 conversion methods
that would pollute the public interface of these types. So it is appropriate to explicitly
implement these members so they are available when cast to IConvertable but do
not appear on the public interfaces.
This makes the development experience much
cleaner.

*
Do expose an
alternative way to access any explicitly implemented members that subclasses are
allowed to override.[1]  Use the
same method name unless a conflict would arise.

The following example shows a type, ViolatingBase, that violates the rule and a
type, FixedBase, that shows a
fix for the violation.

using
System;
 
namespace
DesignLibrary
{
    public
interface ITest
    {
        void
SomeMethod();
    } 
    public
class ViolatingBase : ITest
    {
        void
ITest.SomeMethod()
        {
            // ...
        }
    }
  public class FixedBase :
ITest
    {
        void
ITest.SomeMethod()
        {
            SomeMethod();
        }
 
        virtual
protected void SomeMethod()
        {
            // ...
        }
    }
    public
class Derived : FixedBase, ITest
    {
     override
protected void SomeMethod()
        {
            // ...
            base.SomeMethod();

             // This would cause recursion and a stack
            // overflow.
            // ((ITest)this).SomeMethod();
        }
    }
}

[1] Fully Covered by ExplicitMethodImplementationsInUnsealedClassesHaveVisibleAlternates