In response to a comment on one of my previous posts (Safely Overriding Equals), I've decided to post some comments about Extension methods in general.

A friend asked me what I gained out of extending string to convert to an enum.  He asked, "is it just 'syntactic sugar'?"  The simple answer is, "Yes."  In fact, this is true of many extensions.

Clearly, the major advantage of extensions is changing the syntax of how they are called.  In fact, I have written a few extensions that support chaining and make my code more readable (at least in my mind)

   1: OracleCommand command = GetProcedureCommand( "fas_closing_pkg.GetClosingDealLegs" )
   2:     .WithInputParameter( "pClosingMonth", closingMonth )
   3:     .WithInputParameter( "pDealId", dealId )
   4:     .WithOutputCursor( "oDealLegs" );

So what are extensions?  Well, they are just static utility methods with an extra keyword.  You can even call the extensions as if they are static methods if you really want to.

For Example:

   1: left.SafeEquals( right, test => left.Key == test.Key );
   2: GeneralExtensions.SafeEquals( left, right, test => left.Key == test.Key );

The second line is no different than what you might have written in .Net 2.0.  You may have even written many of these static utilties before and are now enabling them as extensions.

What this means, is that extensions are just static methods behind the scenes.  They are not instance methods.  One implication of this fact is that you must consider that the extended object could be null.  And, if it is null, you will not get an object reference exception when the extension is called.  You could get an exception within the scope of the extension method depending on your implementation.

For example, this is totally legal (generating no runtime errors)

   1: TestClass left = null; 
   2: TestClass right = new TestClass( "right" ); 
   3: Assert.IsFalse( left.SafeEquals<TestClass>( right, test => left.Key == test.Key ) );

Where SafeEquals is implemented as follows:

   1: public static bool SafeEquals<T>( this T left, object right, Predicate<T> test )
   2: {
   3:     if( left != null && right != null && right.GetType().Equals( left.GetType() ) )
   4:     {
   5:         return test( (T)right );
   6:     }
   7:     return false;
   8: }

So, when writing extensions, take a little extra time considering what would happen if the target object is null.

posted on Tuesday, July 8, 2008 11:24 AM
Filed Under [ .Net Design C# ]


No comments posted yet.

Post A Comment