Home > .net 2.0, .net 3.5, c#, LINQ, Visual Studio 2008 > Joys of Extension Methods (and Comparisons)

Joys of Extension Methods (and Comparisons)

October 10, 2007

I’d like to preface this that all methodologies have advantages and disadvantages.  Some methodologies add context and readibility, some add performance gains, etc.—it’s a trade off.

To me, Extension Methods are a fantastic way to either a) add additional functionality very quickly to multiple types, such as the JSON example from a few days ago, or b) add functionality to classes that are sealed or already being consumed, like interfaces and BCL objects such as System.String.  This is how LINQ was implemented in .NET 3.5.

Now, when you add these Extension methods to .NET 3.5’s lambda expressions (I’m a HUGE fan of these… addictive), you can create extremely concise and readable code (in my opinion).

So, let’s start off with a simple list of Strings.😀

List<string> myListOfStrings = new List<string>();

 

myListOfStrings.Add(“Hello”);

myListOfStrings.Add(“World”);

myListOfStrings.Add(“Coding”);

myListOfStrings.Add(“C#”);

myListOfStrings.Add(“Control”);

The trick is, we only want the ones that start with “C”.  In .NET 2.0, you had two ways to do this (well, more if you looped and compared each… but we won’t think of those performance issues).  Both used the Predicate delegate and allowed you to “inline” code, similar to anonymous methods in .NET 3.5 and JavaScript.

// ASP.NET 2.0 – Using the Predicate delegate inline.

foreach (string word in

myListOfStrings.FindAll(

delegate(string thisWord) {

return thisWord.StartsWith(“C”); }))

{

Response.Write(word + “<br/>”);

}

This method was my preferred way to do it if I simply needed a one-time filter, check, or something.  As you can see, the delegate passes the current “list item” as a property and you’re returning a boolean value whether or not to include it in the foreach iteration.

You could also break the delegate logic into another method by constructing a container class.

public class StartsWithLetterChecker

{

public string TextToFind { get; set; }

 

       public StartsWithLetterChecker() { }

       public bool Find(string word)

       {

              return word.StartsWith(this.TextToFind);

}

}

You would then consume that class in your predicate parameter in .FindAll().

// ASP.NET 2.0 – Using the Predicate delegate via method.

StartsWithLetterChecker predicateMethod =

new StartsWithLetterChecker();

 

predicateMethod.TextToFind = “C”;

 

foreach (string word in myListOfStrings.FindAll(predicateMethod.Find))

{

Response.Write(word + “<br/>”);

}

This is very clean and very documented—you know exactly what’s happening, where, and why.  It is, however, more lines of code, but that’d be worth it if the logic is a) heavily used by several predicates, or b) changes often.  You’re also stuck in a box—creating a new class or new method for every permutation (starts with, ends with, contains, etc).

With .NET 3.5, the code monkey has an array of extension methods available to them.  These include:

  • ToList()
  • Where()
  • Union()
  • Contains()
  • Concat()
  • Cast()
  • Count()

There are quite a few more, Object Browse into System.Core.Extension and take a look.  These methods come from System.Core.dll and, similar to .NET 2.0, take a predicate value.  The difference is that in .NET 3.5, we have lambda expressions to save us a lot of hassle.

// ASP.NET 3.5 – Using an extension method and lambda expression.

foreach (string word in myListOfStrings.Where(i => i.StartsWith(“C”)))

{

Response.Write(word + “<br/>”);

}

The “i” is simply a variable and could be most anything (i for iteration, I suppose, or my bad habits).

Now, to those that would complain that you’re losing DRY by putting this logic here rather than encapsulating it in a method similar to the example above.  Well, my answer to that is that this sort of code shouldn’t be (as in the example) at the presentation layer if it could be repetative.  

Extension methods, lambdas, even anonymous methods in .NET 3.5 are not an excuse to get lazy and break OOP, but provide an easier means to accomplish the same tasks AND current code with additional functionality. 

%d bloggers like this: