Sunday, December 22, 2013

Explicit interface implementation Anti-pattern.

Explicit interface definition forces the members to be exposed only when you are working with the interface directly.

The main words are: Unexpected Behavior

Mostly used:
  • Implementing of several interfaces with the same members required different implementation.
  • Struggle with dependencies (very doubtful).
    Code with using more derived types knows nothing about interface's members that were implemented explicitly.
    For example in a ASP.NET MVP (Web Forms) control hide member used by presenter.
  • Work around for having same member with different logic in an interface and its derived class.
  • Some silly protection (by a run-time exception) from using of inappropriate interface members.
    As an example the array's explicit implementation for the ICollection<T>.Add() that will throw the NotSupportedException "Collection of a fixed size".

 Famous drawbacks:
  • It's greasy messy awful coding especially when used without a serious reason.
    It's definitely not an industrial programming.
  • Value type instances will be boxed when casted to an interface.
  • Cannot be called by a derived type
    (What is the struggle with dependencies on the other hand).
  • A virtual chain will be ignored and an explicit implementation will be called.
.
Microsoft's official guidelines (from first edition Framework Design Guidelines) states that using explicit implementations are not recommended, since it gives the code some unexpected behavior.
.
interface IMyInterface
{
    String Implicit { get; set; }
    String Explicit { get; set; }
    String ExplicitAndImplicit { get; set; }
    String OtherExplicit { get; set; }
}


interface IMyOtherInterface
{
 
   String OtherExplicit { get; set; }
}


class MyClass : IMyInterface, IMyOtherInterface
{
 
   String IMyInterface.Explicit { get; set; }

    String IMyInterface.ExplicitAndImplicit { get; set; }
    public String ExplicitAndImplicit { get; set; }

    public String Implicit { get; set; }

    String IMyInterface.OtherExplicit { get; set; }
    String IMyOtherInterface.OtherExplicit { get; set; }
    public String OtherExplicit { get; set; }
}

static void Main(string[] args)
{

    var myObject = new MyClass();
    var myInterface = (IMyInterface) myObject;
    var myOtherInterface = (IMyOtherInterface)myObject;

    myObject.Implicit = "Implicit";

    // Uncompilable code.
    //myObject.Explicit = "Explicit for the MyClass";
    myInterface.Explicit = "Explicit for the IMyInterface";

    myObject.ExplicitAndImplicit = "ExplicitAndImplicit for the MyClass";
    myInterface.ExplicitAndImplicit = "ExplicitAndImplicit for the IMyInterface";
    if(myObject.ExplicitAndImplicit == myInterface.ExplicitAndImplicit)
    {
        throw new Exception("Blow mind");
    }

    myInterface.OtherExplicit = "OtherExplicit for IMyInterface";
    myOtherInterface.OtherExplicit = "OtherExplicit for IMyOtherInterface";
    myObject.OtherExplicit = "OtherExplicit for MyClass";
    if (myInterface.OtherExplicit == myOtherInterface.OtherExplicit
        || myOtherInterface.OtherExplicit == myObject.OtherExplicit)
    {
        throw new Exception("Blow mind");
    }

}
.

No comments:

Post a Comment