Friday, June 1, 2012

Extension methods



Yay! I finally have an excuse to use extension methods.
First, a brief explanation of what they are. Suppose you have an object – say a string. And you want to add some functionality to it. You could subclass the object (assuming it’s not sealed) and add your new method.

But if all you want to do is add one tiny little method, subclassing seems a bit top-heavy, doesn’t it? Besides, unless you’re using an object factory pattern (my favorite design pattern, by the way), you face the prospect of finding and changing every object instantiation in every line of code of your project to replace the parent with the child class. On large, multiple developer projects, this gets rough.

Microsoft gives you a work around. What you can do is to add a special static method somewhere in your code and .Net will automagically assign this to the desired class.

For example,
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ''.''?' },
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
The magic is the keyword “this” in the method signature. “This” tells the compiler that “WordCount” is an extension method on the string object.
The end result is that your code can now do something like:

       string x = "this is a test string";
       Console.WriteLine(x.WordCount());

And the Console will show the word count of x, just as if “WordCount” was a public method on the string class.

I’ve thought this was cool for a long time, but couldn’t find a use for it.

But, Dmytrii Nagirniak posted a reply to a thread on Stack Overflow that provides an awesome use:

http://stackoverflow.com/questions/1725903/determine-if-datacolumn-is-numeric

To sum it up, .Net has no “IsNumber()” method. So looking at a potential data value, it’s really hard to know if it’s a number type. What you end up with, is a complex if statement that does a GetType(), but then has to check to see if the type is a Double OR a Single OR an Int32 OR an Int64 OR a UInt16 OR…. Etc.

Putting this into an extension method makes a ton of sense. (I’m not sure why Microsoft didn’t already do this, frankly). This means that developers don’t need to deal with this mess each time, but just have to call
x.IsNumber().

The code for the extension just looks like this:
  public static Type[] numericTypes = new[] { typeof(Byte), typeof(Decimal), typeof(Double),
        typeof(Int16), typeof(Int32), typeof(Int64), typeof(SByte),
        typeof(Single), typeof(UInt16), typeof(UInt32), typeof(UInt64)};
 
 public static bool IsNumber(this object x)
    {
        if (x == null)
            return false;
      
        return numericTypes.Contains(x.GetType() );
    }

And this allows  you to instantiate any object and define whether the object is a number type.

A second (useful) variation of this examines whether a DataColumn (ie, in a DataTable) is a number type. It’s different because the DataColumn.GetType() would just return “DataColumn, you moron”, so you have to look at “DataColumn.DataType” :
  public static bool IsNumeric(this DataColumn col)
    {
        if (col == null)
            return false;
        return numericTypes.Contains(col.DataType);
    }


Pretty cool stuff.
--kevin

No comments:

Post a Comment