Extension Methods as Mixins

Several sources describe how mixins can be created in C# using (marker) interfaces and extension methods. It goes like this:
public interface IMyTargetInterface 
{
  void Bar();
}

public class SomeTarget: IMyTargetInterface 
{
  public void Bar() { ... }
}

public static class MyTargetExtensions
{
  public static void Foo (this IMyTargetInterface target, ...)
  {
    target.Bar();
    ...
  }
}


It's now easy to see how this can be used:
  SomeTarget t;
  t.Foo(...);


However, note that extension methods are basically just syntactic sugar, the above code looks neat and is more discoverable (when using intellisense), but basically it is no different from
  SomeTarget t;
  Foo (t, ...);


Real mixins are supposed to support the full power of object-oriented programmig, including especially features like polymorphism. Without this, it is little more than well-disguised procedural code.

Using Extension Methods for re-mix

That said, extension can be useful to provide some syntactic sugar for re-mix mixins too:
public class IMyMixin
{
  void Foo();
}

[[Extends (typeof (IMyTargetInterface))]
public class MyMixin : Mixin<IMyTargetInterface>, IMyMixin
{
  [OverrideTarget]
  public virtual void Bar() 
  {
    Next.Bar();
  }

  public virtual void Foo()
  {
    Target.Bar();
  }
}


Powerful as this is, calling the mixin method without any syntacic sugar can be cumbersome and is not very discoverable:
  SomeTarget t;

and either
  var tm = (IMyMixin) t;
  tm.Foo();

or
  ((IMyMixin) t).Foo();

What makes this worse is that these casts cannot be validated at compile time, and if you use ReSharper, it will even warn you that this cast will not work for any type in your solution. (That's true, because the actual type will be generated at run-time.)

Given a small extension method, this can be much nicer:
public static class MyMixinExtensions
{
  public static IMyMixin AsMyMixin (static IMyTargetInterface t) { return (IMyMixin) t; }
}


And now it's just:
  t.AsMyMixin().Foo();


Perfectly discoverable and much more concise. The body of AsMyMixin is still not verifyable, but now you have all these unverifiable casts in a dedicated section of your code. If your "As"-methods are implemented correctly, there will be no runtime surprises from using them. ReSharper users may want to define // ReSharper disable SuspiciousTypeConversion.Global for the offending class.

Last edited Oct 5 at 1:20 PM by stefanwenig, version 2

Comments

No comments yet.