Extension methods in C#

Overview 

Extension methods are a new feature for C# 3.0 and I had the opportunity to implement them in the Compiler. These methods can then be called with instance syntax on any object that is convertible(see convertibility section for details) to the first param of the method.

Validation Extension methods are defined in C# as

static class Extensions

{

  public static IEnumerable<T> Where<T>(this IEnumerable<T> sequence, Predicate<T> predicate)

  {

     foreach (T item in sequence)

     {

        if (predicate(item))

        {

            yield return item;

        }

      }

   }

}

Several Interesting things to Note here

  1. The method is define in a top level static class ( the class is directly under the namespace)
  2. The method is static and decorates its first param with a new param modifier this, this param is called the "instance parameter" and its an error to use the "this" modifiers on any other parameter.
  3. No other parameter modifiers ( ref, out etc) are allowed with "this" (so values types can't be passed by reference to an extension methods, VB will allow ref).
  4. The instance parameter can't be a pointer type.
  5. The method is public (its accessible to anyone who can get to its parentclass).
  6. The Type parameter used must be defined on the method and not the parentclass.

5 & 6 are required because extension methods are bound as instance methods and the argument to instance parameter is the object on which the method is called. This means that the class in which the extension methods are defined is just a container to put the extension method in and will never be involved in binding it as an extension method e.g.

static class Extensions

{

public

static float Average(this System.Array array)

{

float average = 0;

for (int I = 0; i < array.Length; i++)

{

average += (int)array.GetValue(i);

}

return average / array.Length;

}

}

is bound as

int[] array = {34, 56, 100, 45, 23, 12};

array.Average(); note Extensions has nothing to do with the call

      7.  The instance parameter cannot have the type of the Type parameter.

       As this would make the impossible to bind the method as an instance method e.g.

public static class Extension3

{

    public static class Extension4

    {

        public static void Foo<T>(this T inst) { }

    }

}

Convertibility

The following conversion are defined on instance parameter on Extension methods

  1. Identity conversion (type S is S)

  2. Implicit reference conversions

  3. Boxing Conversions

Finding Extension methods

So how is the compiler to know which extension method to bind? The compiler looks for extension methods in the innermost namespace when the call is made for extension methods and then in all the namespaces imported by the "using" clause. This process is followed moving outward until we reach the topmost namespace.

Since extension methods can be imported in to the current context by the "using" clause and bound to any object which is assignable(see convertibility section for details) to the instance parameter, all sorts of interesting possibilities open up for extending the methods implemented by a type. This can simply be done by importing a library of extension methods and using these methods as if they were declared on a type that you don't own. This means that

1. Depending on the library you import the code can be made to do different things.

2. The client gets an interesting way to extend a type that he does not own.

Delegates

Calling methods is all well and good, but do extension methods work when instantiating a delegates?

Of course they do, (here is a good use of curried delegates). If you are not sure what curried delegates ( yum yum Indian food ) are and how to the compiler uses them. Don't be alarmed, i will be covering that in the next post of Extension method binding.

e.g. using the Where extension defined above

double[] array = {34,45,67.12,95,25,69};

Func<Func<double, bool>, IEnumerable<double>> fun = array.Where<double>;

fun(new Func<double, bool>(Pred));

public static bool Pred(double arg)

{

if (arg > 10)

return true;

return false;

}

This works just as long as the instance param is a reference type :) (No Curry for you, Value Type)

Extension methods can also be called on Delegate e.g.

public delegate T del1<T>(T val);

And Extension method Exec defined as

static class Extension

 {

     public static T Exec<T>(this del1<T> source, T param)

     {

      return source(param);

     }

}

We can write client code like 

 

public class Test
{
public static void Main()
{
Test t = new Test();
del1<int> d1 = t.func<int>;
d1.Exec(100);
}

public T func<T>(T val)
{
return val;
}

}

 

This ends the first post on extension methods, next how exactly extension methods are bound.

kick it on DotNetKicks.com