Mixin is a programming language technique in which you extend classes with methods and properties by so called mixins. In C++ mixins are easily achieved using multiple inheritance, while in C# or Java you have to find out how to work around the single inheritance.
There is a long discussion on the matter and people are proposing ways to build mixins in C#. What they usually focus on is extending classes with additional methods (here or here) while, in fact, mixins is not only about methods but also about other class members. In his blog, Colin Mackay has pointed three possible ways to actually build mixin extensions which can hold data.
What I'd like to point out is that there is yet another possibility based on inheritance but this time you inherit from extended classes rather than making them inherit from a base class. In case of structures which are sealed, you just create wrapper classes.
Let's start with the mixin declaration:
interface IMixin
{
int TheProperty { get; set; }
}
static class IMixinExtension
{
public static void Extension1( this IMixin Mixin )
{
Console.WriteLine( "Value of mixin property: " + Mixin.TheProperty.ToString() );
}
}
The interface describes mixin structure while the extension method adds a logic for it. Now we are ready to augment classes.
class StringMixin : IMixin
{
string _string;
public StringMixin( string String )
{
this._string = String;
}
#region IMixin
public int TheProperty { get; set; }
#endregion
#region Conversion
public static implicit operator string( StringMixin Mixin )
{
return Mixin._string;
}
public static implicit operator StringMixin( string String )
{
return new StringMixin( String );
}
#endregion
#region Delegated methods
public override string ToString()
{
return _string.ToString();
}
public string ToLower()
{
return _string.ToLower();
}
// etc...
#endregion
}
As you can see it's not quite ellegant because there's no default delegation so I cannot delegate methods from System.string to the _string member of the class, however from the client's point of view, StringMixin is just a string with additional properties:
class StringClient
{
public static void ExpectsString( string String )
{
Console.WriteLine( String );
}
}
class Program
{
static void Main( string[] args )
{
StringMixin mixin = "The string";
StringClient.ExpectsString( mixin );
}
}
On the other hand, extended class behaves just as mixin is supposed to behave: it has been augmented with additional members but base members are still there:
class Program
{
static void Main( string[] args )
{
StringMixin mixin = "The string";
// it's still a string
Console.WriteLine( mixin.ToLower() );
// but augmented with properties
Console.WriteLine( mixin.TheProperty.ToString() );
// and methods
mixin.Extension1();
}
}
Note that since the original class is wrapped, the wrapper can contain any additional data so the "dataless mixins" issue is gone.
The drawback is obvious : you need extra wrapper class for each class you'd like to augment with a mixin. Note that in case of reference types there's no need to wrap - instead of wrapping the class you can just inherit from it.
No comments:
Post a Comment