Much of my code play recently has been with .NET/Mono in C#. One of the cooler aspects of 3.x has been extension methods by which I can add methods to established types. For instance if I'm doing a bunch of range checking on integers the traditional way would be:
if ((3 <= i) && (i <= 9))
{
...
}
With extension methods I can create an extension that allows me to do:
if (i.Within(3,9))
{
...
}
I do this by creating a static class like below:
static class MyExtensionMethods
{
public static bool Within(this int me, int a, int b)
{
// this is faster if we require a to be the
// lower bound and b to be
// the upper bound, but to be complete...
return (Math.Min(a,b) <= me) &&
(me <= Math.Max(a,b));
}
}
The tricky part is applying this to certain types such as enumerations. One thing I do a lot with enums is testing if an or'd set contains one given enum value. For instance to determine if the left mouse button is pressed I would use:
if ((Control.MouseButtons & MouseButtons.Left) ==
MouseButtons.Left)
{
// Handle the left button down
}
So I can create an extension method for MouseButtons enum:
public static bool Contains(this MouseButtons me,
MouseButtons other)
{
return (me & other) == other;
}
That's handy but I don't want to create this for every enum I touch. So now I want to create an extension method that extends any enum. The first try is:
public static bool Contains(this Enum me, Enum other)
{
return (me & other) == other;
}
This works but I can do Control.MouseButtons.Contains(MenuMerge.Add) which might work but isn't really valid. So let's try to change it:
public static bool Contains(this T me, T other)
where T : enum
{
return (me & other) == other;
}
This is how it should work, however MS in all their wisdom has decided enums cannot be set as a where statement on methods or classes. So we have to cheat and introduce some possible problems that wouldn't show up until run time. We can use a struct as a where clause and enums are structs, but then we have to test that the type T is actually an enum. This leads to the final form:
public static bool Contains(this T me, T other)
where T : struct
{
if (!typeof(Enum).IsAssignableFrom(typeof(T)))
thrown new InvalidCastException();
return (me & other) == other;
}
This works, but the compiler won't throw an exception on using the Contains method on regular structs. You will get a run time exception but that can be messy so use at your own discretion.
No comments:
Post a Comment