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
- The method is define in a top level static class ( the class is directly under the namespace)
- 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.
- 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).
- The instance parameter can't be a pointer type.
- The method is public (its accessible to anyone who can get to its parentclass).
- 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
Identity conversion (type S is S)
Implicit reference conversions
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.
Comments
Anonymous
April 25, 2007
When you say "6. The Type parameter used must be defined on the method and not the parentclass." what do you mean by "Type parameter"? I'm not sure which parameter this refers to, is it the type of the instance parameter? or some other parameter?Anonymous
April 26, 2007
That method is generic so it has a type parameter list (the names between < and > are the type parameters). So when he says "the Type parameter" he is referring to the T. You can also make generic classes, that's when the class itself has a type parameter list. Number six is saying that with extension methods you can't use any type parameters from the containing class only type params from the (generic) extension method.Anonymous
April 26, 2007
There's no way to add static methods or new operators using Extension Methods is there?Anonymous
April 26, 2007
All Extension methods are static methods and can be called as such. No extension methods can't be operator they are always bound as methods. Object.ExtensionName(arguments .... )Anonymous
April 27, 2007
Sure the extension methods themselves are static methods, but they appear as instance methods on the type being extended. Is there a technical reason why you couldn't extend types with new static methods (and operators) or was this just a design decision to support the minimal amount necessary to make LINQ work nicely?Anonymous
April 29, 2007
The comment has been removedAnonymous
May 08, 2007
You've been kicked (a good thing) - Trackback from DotNetKicks.comAnonymous
May 11, 2007
I open a codeplex project for an Extension Methods library : http://www.codeplex.com/ExtensionMethodsAnonymous
May 13, 2007
Welcome to the 27th Community Convergence. I use this column to keep you informed of events in the C#Anonymous
June 09, 2007
Plz expalin me from where this thing came from We can write client code like del1<int> d1 = t.func<int>;Anonymous
June 21, 2007
Sorry for the incomplete example ... basically we are creating an delegate and calling the extension method Exec on it. The important information missing is the defintion of the method func that created the delegate. public class Test { public static void Main() { Test t = new Test(); del1<int> d1 = t.func<int>; Console.WriteLine(d1.Exec(100)); } public int func() { return 10; } public T func<T>(T val) { return val; } }Anonymous
September 03, 2007
We started using some of the new C# 3.0 features with our functional web testing tool InCisif.net, including extensions methods and lambda expression. Our goal is to be able to simplify the test code. And it is great. see our posts : http://blog.incisif.net/2007/09/02/incisifnet-20-and-c-30-lambda-expression.aspx http://blog.incisif.net/2007/05/28/orcas-net-35-and-c-30.aspx Feedback welcome.Anonymous
September 16, 2007
I did a french webcast about extension methods: ftp://ftp-developpez.com/matthieumezil/webcasts/ExtensionMethods.wmvAnonymous
January 16, 2008
re: 拡張メソッドなら、this == null でもいい。Anonymous
March 11, 2008
hi can you plaese explain me, how can we add images using the extension methods.........Anonymous
March 13, 2008
avantika, i am not sure i understand. Extension methods add a usefull call symatics, its up the user to implement whatever they want in the method body.Anonymous
June 18, 2008
Thanks for the thorough description. Just what I was looking for.Anonymous
November 27, 2008
Hello, today I have tried to add some methods mathematical notation to my classes to work on voxel volume data. I wanted to implement an operator * which works on the volume. Is it possible to use extension methods to add some operator functions?