Thursday, January 19, 2012

Quick tip, Respecting your own contract.

I wish C# was smart enough to figure this out by itself, perhaps it is but I haven't found out how to get it to cooperate. I like using interfaces as a contract for how code should behave. I also default to using explicit interface implementation to enforce this contract. Where this gets a little annoying is when adopting a DNRY attitude and trying to reference an interface implemented method/property from within the same class.

Ultimately there are two approaches:
#1. Interface implementations call private methods. This is pure enough but I really don't like duplicating method signatures, one for the interface, and a second private method that does the work.
----
public class MyClass : IMyInterface
{
    IEnumerable IMyInterface.LookupMyNames()
    {
       return LookupMyNames();
    }
    private IEnumerable LookupMyNames()
    {
       // Do stuff....
    }
    string IMyInterface.GetCombinedName()
   {
      var names = LookupMyNames();
      // Do stuff...
   }
----
#2. Access the implementation by casting "this" to the interface. This avoids the extra method declarations but frankly looks hideous.
----

public class MyClass : IMyInterface
{
    IEnumerable IMyInterface.LookupMyNames()
    {
       // Do stuff....
    }
    string IMyInterface.GetCombinedName()
   {
      var names = ((IMyInterface)this).LookupMyNames();
      // Do stuff...
   }
----
Another option that's a bit easier on the eyes in my mind is to use a private property to expose the class to itself through its interface.
----
public class MyClass : IMyInterface
{
    private IMyInterface This
    {
      get{ return (IMyInterface)this;}
    }
    IEnumerable IMyInterface.LookupMyNames()
    {
       // Do stuff....
    }
    string IMyInterface.GetCombinedName()
   {
      var names = This.LookupMyNames();
      // Do stuff...
   }
----

Obviously this only works well in cases where a class is primarily interested in implementing a single interface, however when using contracts in this way this is almost exclusively the case. You can of course expose a property for each interface using some form of naming convention. I used "This" since it has meaning, but perhaps "AsIMyInterface" is your taste....

No comments:

Post a Comment