Browsing through my current project, I ran across some code similiar to this (but much longer):
var myInt=3;
if( someCondition && someOtherCondition&& (myInt==1||myInt==3||myInt==5) )
{
doSomething();
}
I hate really long if()s. So, this lead me to think along the lines that there’s got to be a better way to do this. 3 separate statements all checking the value of a single variable is excessive in my mind. I wanted the code to read like this to simplify the conditions and make them more readable:
var myInt=3;
if( someCondition && someOtherCondition && myInt.IsIn(1,3,5) )
{
doSomething();
}
In many other languages the above would be impossible, we’d have to write IsIn(myInt,1,3,5) which isn’t as intuitive to read. However, as of version 3 or 3.5, .NET allows us to write extension methods so that we can write the code exactly as I outline above. In order to write an extension method, you have to have 3 things: a static class, a static method, and the first parameter of the static method needs to have the “this” keyword before the parameter and be of the type that you wish to extend. So, to create a method that does exactly what’s shown above, we could do it like so:
public static class Int32Extensions
{
public static bool IsIn( this Int32 number, params Int32[] values )
{
foreach( var value in values )
{
if( number==value ) return true;
}
return false;
}
}
Using the “this” keyword in a static method and class allows you to use the method as-if it were part of the Int32 class. If you’re unfamiliar with it, the second parameter also has some magic with the “params” keyword. My co-workers told me about this while I was working on this method which saved me from writing overloads for 2, 3, and 4 parameters. The params keyword can be used as the last parameter of a method to allow an unspecified number of parameters to be sent in as an array of a specific type, which keeps you from having to do: myInt.IsIn( new[]{1,3,5} ). You can look into it further if you like by clicking here.
So, this method leverages extension methods and will let you assign any number of parameters to check against, which is great. However, the problem with this is that it’s only going to be able to be used by the Int32 object. The result would be that if I wanted to do the same thing for other types, I would need to write an overload for them. So, I’d end up with overloaded methods for Int64, Decimal, String, and maybe a number of my Enums, etc. I could easily end up with 10 or more overloaded methods that all do exactly the same thing. On the other hand I could write the extension method so that it extends object instead of Int32, but then my code would no longer be strongly typed, and it could result in unforeseen runtime issues. So, this brings us to Generics. If we change this method as follows, it can be used by ANY object and still require all parameters to be of the same type as the object we are comparing against:
public static class GenericExtensions
{
public static bool IsIn<T>( this T instance, params T[] values )
{
foreach( var value in values )
{
if( instance.Equals(value) ) return true;
}
return false;
}
}
The “T” generic here: IsIn<T>( this T instance ) makes this extension method available to ALL objects. By using “params T[] values” we are requiring that the parameters passed into the method for comparison are of the same type as the object being compared against, keeping us from runtime issues where things would be equal but aren’t because they’re not the same type. We now have a very powerful method, and if you are working in the same namespace or use the namespace in your file, you’ll see the IsIn method show up in your Intellisense in Visual Studio. So, this method is now extremely re-usable and can make multiple conditional checks against the same variable much more readable.
However, there is one more thing that can make this code even cleaner. I was quite happy with the above method and would have stopped there. However, I have Resharper installed, and it was underlining the foreach. So, I hovered over it, and it was telling me to change it to a LINQ expression. So, having learned to trust ReSharper a bit, I decided to click the little lightbulb icon next to it and let it reformat my method, which changed my code to this:
public static class GenericExtensions
{
public static bool IsIn<T>( this T instance, params T[] values )
{
return values.Contains(instance);
}
}
I love ReSharper…it’s the only application I’ve ever had that actually taught me programming tips & tricks on the fly. As a result, I have an extension method that uses Generics so that it can be used by ANY object, using the params keyword so that I can pass in any number of parameters to compare against, and using LINQ so that my method is extremely short and readable.
Now, there are other ways to skin this cat that don’t involve coding an IsIn method, such as: “new[]{1,3,5}.Contains(myInt)”, but I think that the IsIn adds quite a bit to readability over doing that.
Anyway, hopefully this little tidbit will help someone.