in Development

C# 3.0 – Extension Methods

Extension methods are a very cool feature. They are special static methods that can be used as if they were instance methods. What does it mean from our developer perspective? That we can simulate we add new methods to existing types.

It's quite common to find an existing class we want to extend with some new features. The alternatives to extend a class in this situation are limited, normally we will inherit from the class we want to extend, we will use a decorator pattern over it or we will embed the class in a wrapper. These techniques can be very useful, but sometimes they are not exactly what we really want to do.

Let's say you want a method that allows you to sort an array of int descending, the easiest approach you probably will use is to create a static method SortDesc that receives an int array as parameter and contains the logic to sort the array. Something similar to:

   1: static void Main(string[] args)
   2: {
   3: 
   4:     int[] numbers = new int[] { 1, 2, 3, 4, 5, 6 };
   5: 
   6:     SortDesc(numbers);
   7: 
   8:     foreach (int number in numbers)
   9:     {
  10:         System.Diagnostics.Debug.WriteLine(number);
  11:     }
  12: }
  13: 
  14: public static void SortDesc(int[] numbers)
  15: {
  16:     if (numbers != null && numbers.Length > 1)
  17:     {
  18:         bool sorted;
  19:         do
  20:         {
  21:             sorted = true;
  22:             for (int i = 0; i < numbers.Length; i++)
  23:             {
  24:                 if (i < numbers.Length - 1 && numbers[i] < numbers[i + 1])
  25:                 {
  26:                     int tmp = numbers[i];
  27:                     numbers[i] = numbers[i + 1];
  28:                     numbers[i + 1] = tmp;
  29: 
  30:                     sorted = false;
  31:                 }
  32:             }
  33:         } while (!sorted);
  34:     }
  35: }

With extension methods, we can rewrite the code in a way that the call to SortDesc is done as any other method of the class int[], like GetLength or GetLongLength. To do it we need we just need to apply the right syntax.

To declare an extension method we need include them in a static class, to specify the type we are going to extend we should set the modifier "this" before the first parameter of the method, being the type of the first parameter the type we are extending, in our case int[]. Once this is done we only need to import the namespace where we have created the static class, and all the int[] variables we use in the context will benefit of our new SortDesc method, and the coolest thing is that we will have intellisense for them. Look the code below.

   1: using Blog.Utilities;
   2: 
   3: static void Main(string[] args)
   4: {
   5:     int[] numbers = new int[] { 1, 2, 3, 4, 5, 6 };
   6: 
   7:     // New method invoke!!!
   8:     numbers.SortDesc();
   9: 
  10:     // Traditional method invoke!!!
  11:     Extensions.SortDesc(numbers);
  12: 
  13:     foreach (int number in numbers)
  14:     {
  15:         System.Diagnostics.Debug.WriteLine(number);
  16:     }
  17: }
  18: 
  19: namespace Blog.Utilities
  20: {
  21:     // Static class
  22:     public static class Extensions
  23:     {
  24:         // Note the "this" modifier before the parameter
  25:         public static void SortDesc(this int[] numbers)
  26:         {
  27:             // Method body
  28:         }
  29:     }
  30: }

If you look the line 11 you can see that the old syntax can be used to invoke the method, in fact the IL code generated proves that the compiler just translates the new invocation to the old one.

IL_0013: ldloc.0
IL_0014: call void Blog.Utilities.Extensions::SortDesc(int32[])
IL_0019: nop
IL_001a: ldloc.0
IL_001b: call void Blog.Utilities.Extensions::SortDesc(int32[])

The last thing we must know about Extension Methods is that their visibility is lower than instance methods, this means that if we have an instance method and an extension method, with the same parameters for the same type, the instance method will have preference over the extended one.