How Myxin Works

In object oriented languages, you have basically two ways of integrating behaviour in a class:
  • By implementing methods in the class body
  • By inheritance from a base class

Obviously, the first method is the easiest when the beahviour you need is new, and the second is the easiest when you already have a base class implementing what you need.

Unfortunately, if you have a class that needs to borrow behaviour from two different base classes, you are in trouble because .NET does not allow for multiple implementation inheritance: you must inherit from one class, and add the methods of the second behaviour in the class body, which incurs multiple copies of the same code.

To ease this, you usually implement the second behaviour in a helper class, and add hooks to your main classes that delegate to the helper class. However, you still have to write the hooks over and over again in your main classes...

An example

I have a program where I need to implement drag-and-drop in custom controls.

Doing so is not really difficult, but you have to intercept multiple events, track the position of the mouse, etc... so I decided to write a base class DragAndDropControl that containted all that logic, then derive my actual controls from DragAndDropControl.

This worked fine until I decided to implement one of the control as a User Control rather than a Custom Control. I cannot inherit from both UserControl and DragAndDropControl, so I had to cut and paste code from DragAndDropControl to DragAndDropUserControl, and maintain both copies.

Enter ... Mixins

This is where I decided that it was too cumbersome, and that I needed a tool to manage this code copying for me. This evolved to a simple pattern to inject code in the class body, similar to Mixins.

A mixin is a class implementing some behaviour that you can inject in another class. Basically, you include the methods from the mixin into your own class.

I wanted this to be as simple as possible:
  • The injected code needs to be easily debuggable
  • The injected code needs to be visible by IntelliSense
  • The solution needs to be useable from any IDE, and especially Visual Studio Express, which lacks the possibility to add plugins.

The principle

The solution I came with is very simple:
  • Your class is implemented in multiple source code files.
  • One of the code file has the same name as your class (as usual) and contains your hand-written code.
  • Additional code files, with a specially crafted name, contains the code imported from mixin classes.
  • A simple tool creates the additional code files automatically from templates.

Step by step

Your classes should inherit from one of the base classes providing behaviour. In my case, my class DragAndDropUserControl needs to inherit from UserControl, and DragAndDropControl needs to inherit from Control:

DragAndDropControl.cs :
  public partial class DragAndDropControl : Control
  {
     ...
  }

DragAndDropUserControl.cs :
  public partial class DragAndDropUserControl : UserControl
  {
    ...
  }

Note the use of the partial keyword that basically the class is implemented in multiple source code files.

We can now add more source code files that contain more code for the same class. By convention, I call these files Classname.Mixin.MixinName.cs . In our case, the Mixin name is "DragAndDrop":

DragAndDropControl.Mixin.DragAndDrop.cs:
  public partial class DragAndDropUserControl
  {
    // Shared code to handle drag and drop
  }

DragAndDropUserControl.Mixin.DragAndDrop.cs:
  public partial class DragAndDropControl 
  {
    // Shared code to handle drag and drop
  }

Note that, except for the class name, these two files are exactly the same, so they can be generated automatically from a template file. There are many ways of generating a source file from a template. The most well known is the C preprocessor where you can include header files, replace text using macros, etc. so it would be a simple matter of writing:

DragAndDropControl.Mixin.DragAndDrop.cs:
  public partial class DragAndDropUserControl
  {
    #include "DragAndDrop.h"
  }

DragAndDropUserControl.Mixin.DragAndDrop.cs:
  public partial class DragAndDropControl 
  {
    #include "DragAndDrop.h"
  }

Unfortunately, the C# preprocessor does not support file inclusion, so you need to use an external tool. Several such tools exist, and one of the best is already available in Visual Studio : T4. However, it is not readily available in Visual Studio Express, and its syntax is a little too complicated for what I intended to do....

Myxin

So, I wrote a little utility program that does minimal templating: it enumerates all files in a directory, and each file with a name in the form of A.Mixin.B.cs is considered an automatically generated file from a template. I chose to name the template file BMixin.cs. When copying the template to the actual file, every instance of the term BMixin is replaced by A.

In our example, there should be a file named DragAndDropMixin.cs implementing the drag and drop feature:

DragAndDropMixin.cs:
public partial class DragAndDropMixin
{
   override void OnMouseDown (...)
   {
      ...
    }
    ....
}

Note that contrary to T4 templates or .h files, this template file is a perfectly valid C# source file. This means that you can edit it in Visual Studio, use Intellisense and syntax colouring as usual.

Re-generating the mixin files

Every time you change the implementation of the mixin class, you should re-generate the additional files. To do so, simply run Myxin.exe in your source directory. It will automatically re-generate all files. *Beware that this will overwrite any file that is recognized as a generated file, ie files with .Mixin. in their name.

The easiest way to do so is to copy Myxin.exe in your source directory (it is shorter than your average source file :-) ), and add it as a pre-build task on your project.

Last edited Jan 7, 2010 at 1:16 PM by sleclercq, version 1

Comments

No comments yet.