Sunday, January 20, 2008

Pseudo Multiple Inheritance in C# 3.5

I used to think that extension methods were nothing more than a LINQ facilitator that were to be avoided in day-to-day class design.  I had visions of IntelliSense drop-downs filled with hundreds of utility methods for the String type, or, worse yet, object.  I could see junior level programmers becoming dependent on these methods, only to become disappointed when they couldn't find them after having moved on to a new project.

And then I came across Bill Wagner's post on MSDN that explains how to Create Mixins with Interfaces and Extension Methods.  It got me thinking about this new feature of C# 3.5 some more.  If you haven't read his article yet, stop now and do so before continuing.

The points Bill makes are great, but I think he danced around what could be the biggest benefit of extension methods: pseudo multiple inheritance in C# (well, sort of).  If you take Bill's method of encapsulation, and apply it to multiple interfaces, you end up with discrete collections of inheritable functionality that can be mixed and matched like Legos.

I'll demonstrate this possibility with everyone's favorite eating utensil: the spork.  I'll be using Bill's "minimalist interface paired with a mixin" approach.



public interface IFork { }
public static class IForkMixIns
{
public static void SpearFood(this IFork fork)
{
Console.WriteLine("IFork: Got it!");
}
}
public interface ISpoon { }
public static class ISpoonMixIns
{
public static void ScoopFood(this ISpoon spoon)
{
Console.WriteLine("ISpoon: Got it!");
}
}

public class Spork : IFork, ISpoon { }

Now an instance of Spork will have both the SpearFood() and ScoopFood() behaviors.

I even have pseudo method overriding with this approach as well (i.e. overriding one of the mixed-in methods).  All I have to do is implement a method of the same signature on the inheriting class--no override/new required.  As an example, I'll warn the spork users about the tines when they attempt to use it as a spoon (just in case they were expecting a smooth edge).



public class Spork : IFork, ISpoon
{
public void ScoopFood()
{
ISpoon spoon = this;
spoon.ScoopFood();
Console.WriteLine("Spork: Watch out for the tines!");
}
}

Of course this isn't a true override; it's more like using the new keyword.  Casting a Spork to an ISpoon will still result in the definition of ISpoonMixIns.ScoopFood() being used.

And that brings me to the obvious limitation of this strategy.  The title of this post includes the phrase "pseudo multiple inheritance" for a reason.  Since true method overriding is not supported, opportunities to take advantage of the polymorphic capabilities of the concrete classes are more limited.