Pages

Sunday, January 16, 2011

Internals of Extension Methods

Hi folks,

It is nice to see people likes my post so much. Ever since I wrote about “Internals of Delegates” there is a large hits on my site and people wanted me to continue posting few more internals like that. Even I was thinking the same, I was confused what I should start for my next topic. Finally, I have decided to speak about another important C# feature that we use very often called Extension Methods and try to look deep into its facts. Lets first demonstrate the basics of Extension methods first and later we will dive deep into it. If you are comfortable with Extension Methods, please skip the following section.

The Basics

Extension method is actually defined as static but acts as an instance specific method. In other words, even though the code that is running inside the Extension method is not declared within the scope of the class, it is still associated with an instance of an object for that particular class. Extension method does not need to be in the same namespace where the actual type is. Hence you can easily add extension method anywhere outside the namespace and any other static class. The namespace which when added to the code will automatically add those extension methods and call appropriately for an existing type. Extension methods can also be thought as extension to a pre-existing type.



For instance, let me define a class first :
public class MyClass
{
    public int MyMethod()
    {
        Random rand = new Random(100);
        return rand.Next();
    }
}
This is a very simple class with one method MyMethod which returns an integer value. Now how to extend the class to add another method say MyMethod2. There are a couple of option available for you, either you need to extend this class to another type MyClass2 derived from MyClass and include that method into it, or use extension method to add it directly within the type MyClass itself.

public static class Extensions
    {
        
        public static int MyMethod2(this MyClass obj)
        {
            return 10;
        }
    }

MyMethod2 is now an extension method which is included with MyClass. You should remember that Extension method is static with the first argument being of Type in which the method is to be included with a “this” keyword in front of it. This identifies it as an extension method. Any parameter can be passed normally after the first argument.
By the way, you can even make MyClass sealed (Not extensible), yet you have the option to use extension method to extend the type.

Note : By using extension method you can extend any type, even from the BCL.

Calling an Extension method

Well, there is nothing as simple as we could speak about calling an extension method. There is no extra thing that you need to do when you call an extension method. Extension method is called just the same way as you call a normal instance method. The compiler automatically replaces the call to provide appropriate method binding.

MyClass tobj = new MyClass();
    Console.WriteLine("Value from Instance method : {0}",tobj.MyMethod());
    Console.WriteLine("Value from Extension method : {0}", tobj.MyMethod2());
    Console.Read();


You can even add extension method to any known Types.

public static byte[] GetBytes(this string thestring)
{
    return Encoding.ASCII.GetBytes(thestring);
}

Here every string you declare will automatically add GetBytes method into it.


Internals of Extension method

Now as you know the basics of Extension methods lets go a little depth. The first thing that I would like to share with you is how a method is actually called in IL for extension method.

MyClass tobj = new MyClass();

tobj.MyMethod();
tobj.MyMethod2();
Extensions.MyMethod2(tobj);

Now let us look into three calls in IL.


So if you demonstrate the three lines in IL, it is evident that the last two calls are exactly the same while the first is instance specific call. The C# compiler translates the call exactly the same way as if we call the static method directly. The first call is the general call to the MyMethod member, which uses callvirt (to ensure it is latebound) while the next two methods invokes a call (strictly compile time bound) .

So what is the main advantage of having extension method then if it produces the same MSIL as if we do call it normally? Is there any specific advantage we get if we create an extension method ? Lets demonstrate the IL for Extensions class.

We put two methods in Extensions class, such that the class looks like :
public static class Extensions
    {
   
        public static int MyMethod1(MyClass obj)
        {
            return 10;
        }
        public static int MyMethod2(this MyClass obj)
        {
            return 10;
        }
    }

So the MyMethod1 is the same replica to MyMethod2, the only difference is that MyMethod2 is an extension method. Now if you dissemble the code it will look like :


You should notice, in the actual IL, the only thing that differentiate between the two method is the presence of ExtensionAttribute in MyMethod2. MyMethod2 creates an object of custom ExtensionAttribute class.

So you should be clear, the compiler just puts an ExtensionAttribute to both the class and the Extension method and the code that I think might produce this IL would look like :

[Extension]
    public static class Extensions
    {
   
        public static int MyMethod1(MyClass obj)
        {
            return 10;
        }
        
        [Extension]
        public static int MyMethod2(MyClass obj)
        {
            return 10;
        }
    }
Strange rules to the Compiler, C# gives you an error saying you should not use Extension attribute, rather use this syntax instead.

Now as we get through with this, lets demonstrate the power of the compiler while translating the Extension methods into IL. Let me cast the method into a delegate.

Func<int> action = tobj.MyMethod2;
object t = action.Target;
Console.WriteLine(t);

If you see the output to this, its MyClass rather than null. Now lets see how IL looks like :


Again, this is very unnatural. The compiler again writes this for us. The delegate Func receives the object as first argument (as Target). Hence the Target for extension method behaves appropriately(as instance method). Neato!!!

[Note : Does it relates to Adapter Pattern?]

Just few minutes back Zenwalker asked me about the relationship between Adapter pattern and Extension Methods. Well, in fact I think there is no relation between the two, even though both creates Type wrappers. Adapter pattern being a design pattern introduces Wrappers to make one type compatible with another using a common interface between the two; While Extension methods is language feature and it allows a type to extend its hierarchy.



Conclusion

That’s all Folks. Even though I tried a little more to check MethodInfo.GetCurrentMethod() it seems to be nothing to talk about it. Extension method is a language feature (not a CLI change) and MS guys did great to make it more useful. I liked it.

Thanks for reading.

6 comments:

  1. The article is kool. Just my findings,
    Func action = tobj.MyMethod2; gives error as its not convertable.

    And thanks for clarifying my Adapter vs Extension doubt again. :)

    ReplyDelete
  2. @Zenwalker

    It should be

    Func<int> action = tobj.MyMethod2;

    The article strips down the angular braces :)

    ReplyDelete
  3. Hi Abhi,
    Sorry, even with angle braces my VS2010 giving error.
    Im doing some ting wrong. :O

    ReplyDelete
  4. @Abhishek Sur
    As I thought, you might be doing

    Func action = tobj.MyMethod2():

    you should remove the open braces.

    ReplyDelete
  5. Hi Abhi, got a bit doubt while luking into dept.
    If "this" is present in the argument, the IL has this line
    .custom instance void System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )

    I am kinda not able 2 understand this line. It wont appear if "this" isnt present in the argument.

    Whats that strange numbers at the end viz (01 00 00 00)

    Thanks

    ReplyDelete
  6. @Zenwalker

    Think of this line as an Extension attribute for the method.

    [Extension]
    public int ...

    ExtensionAttribute constructor is been called inside the Method.

    The (01 00.... number sequence represents the hexadecimal bytes. Please read

    http://books.google.co.in/books?id=oAcCRKd6EZgC&lpg=PA329&ots=KzYe8EtY2q&dq=why%20constructor%20is%20assigned%20to%20in%20IL&pg=PA329#v=onepage&q=why%20constructor%20is%20assigned%20to%20in%20IL&f=false

    about those info(custom Attribute section).

    I hope you will get it.

    ReplyDelete

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.