Is it possible to implement mixins in C#?

Viewed 35767

I've heard that it's possible with extension methods, but I can't quite figure it out myself. I'd like to see a specific example if possible.

Thanks!

10 Answers

It really depends on what you mean by "mixin" - everyone seems to have a slightly different idea. The kind of mixin I'd like to see (but which isn't available in C#) is making implementation-through-composition simple:

public class Mixin : ISomeInterface
{
    private SomeImplementation impl implements ISomeInterface;

    public void OneMethod()
    {
        // Specialise just this method
    }
}

The compiler would implement ISomeInterface just by proxying every member to "impl" unless there was another implementation in the class directly.

None of this is possible at the moment though :)

There is an open source framework that enables you to implement mixins via C#. Have a look on http://remix.codeplex.com/.

It is very easy to implement mixins with this framework. Just have a look on the samples and the "Additional Information" links given on the page.

LinFu and Castle's DynamicProxy implement mixins. COP (Composite Oriented Programming) could be considered as making a whole paradigm out of mixins. This post from Anders Noras has useful informations and links.

EDIT: This is all possible with C# 2.0, without extension methods

I've found a workaround here, which while not entirely elegant, allows you to achieve fully observable mixin behavior. Additionally, IntelliSense still works!

using System;
using System.Runtime.CompilerServices; //needed for ConditionalWeakTable
public interface MAgeProvider // use 'M' prefix to indicate mixin interface
{
    // nothing needed in here, it's just a 'marker' interface
}
public static class AgeProvider // implements the mixin using extensions methods
{
    static ConditionalWeakTable<MAgeProvider, Fields> table;
    static AgeProvider()
    {
        table = new ConditionalWeakTable<MAgeProvider, Fields>();
    }
    private sealed class Fields // mixin's fields held in private nested class
    {
        internal DateTime BirthDate = DateTime.UtcNow;
    }
    public static int GetAge(this MAgeProvider map)
    {
        DateTime dtNow = DateTime.UtcNow;
        DateTime dtBorn = table.GetOrCreateValue(map).BirthDate;
        int age = ((dtNow.Year - dtBorn.Year) * 372
                   + (dtNow.Month - dtBorn.Month) * 31
                   + (dtNow.Day - dtBorn.Day)) / 372;
        return age;
    }
    public static void SetBirthDate(this MAgeProvider map, DateTime birthDate)
    {
        table.GetOrCreateValue(map).BirthDate = birthDate;
    }
}

public abstract class Animal
{
    // contents unimportant
}
public class Human : Animal, MAgeProvider
{
    public string Name;
    public Human(string name)
    {
        Name = name;
    }
    // nothing needed in here to implement MAgeProvider
}
static class Test
{
    static void Main()
    {
        Human h = new Human("Jim");
        h.SetBirthDate(new DateTime(1980, 1, 1));
        Console.WriteLine("Name {0}, Age = {1}", h.Name, h.GetAge());
        Human h2 = new Human("Fred");
        h2.SetBirthDate(new DateTime(1960, 6, 1));
        Console.WriteLine("Name {0}, Age = {1}", h2.Name, h2.GetAge());
        Console.ReadKey();
    }
}

There are, fundamentally, several techniques to getting Mixin behavior in your classes:

  • Behavioral mixins that hold no state are easily done using extension methods
  • Behavioral mixins for interfaces that use duck typing (currently, IEnumerable and IDisposable) can use default interface members with explicit implementation of said interface. Then, then new interface behaves as a mixin where concrete behavior can be added and leveraged without using extension methods, and can support constructs such as using and foreach.
  • Mixins that need state can be implemented very roughly by using extension methods and a static ConditionalWeakTable to hold data.
  • Multiple inheritance mechanics can be crudely synthesized at compile-time (T4, source generators) or runtime (Reflection.Emit).
Related