RSS

How extension methods implemented in .NET

18 Oct

In one of my previous posts I wrote about “Adding Extension Methods to Every Object in C#”. So how does extension methods internally implemented?
In essence extension methods are surprisingly compiler tricks and the code generated is pretty much ordinary static method calls! To get better understanding about this we need to look at the IL generated by the code. My favorite tools for this task are ILSpy, Teleric free just in compiler or simply ILDasm. I use these tools interchanging.

Consider following extension method,

namespace System
{
   public static class ObjectExtensions
   {
      public static string ToJson(this Object obj)
      {
         return JsonConvert.SerializeObject(obj);
      }
   }
}

And consider simple usage of it on here,

namespace Extensions.Tests
{
   [TestFixture]
   public class ObjectExtentionTests
   {
      [Test]
      public void Object_Extention_ConvertToJSON_Test()
      {
         var p = new Person() { FirstName = "Dimuthu", LastName = "Perera"};
         Debug.Write(p.ToJson());
      }
   }

   public class Person
   {
      public string FirstName { get; set; }
      public string LastName { get; set; }
   }
}

If you load this built output assembly containing this test code to ILSpy as shown in following. I have

highlighted IL code that is calling “ToJson()” to method.
extension methods IL1

extension methods IL2
The code is this,

IL_0022: call string [Extensions]System.ObjectExtensions::ToJson(object)

As you can see this is actually a static method call to “ToJson” method inside static System.ObjectExtensions class. Actually exactly the same IL as above will be generated when you just write a static method in ObjectExtensions class and call it by passing any object to it! So extension methods are kind of programmer friendly “syntactic sugar”. So code generated by compiler is exactly the same for method calls if you have written it as following. Note that we do not use “this” keyword to distinguish the method as extension method.

namespace System
{
	public static class ObjectExtensions
	{
		public static string ToJson(Object obj)
		{
			return JsonConvert.SerializeObject(obj);
		}
	}
}

So my test method becomes as following,


                [Test]		
                public void Object_Extention_ConvertToJSON_Test()
		{
			var p = new Person() { FirstName = "Dimuthu", LastName = "Perera"};
			Debug.Write(ObjectExtensions.ToJson(p));
		}

Note now we are passing object as an argument to the static method. If you disassembly this and inspect IL you will find that the IL for these method calls are same as when we use extension methods.

So how does the compiler knows a method is an extension method or not? Answer is clever C# compiler knows it by looking “this” keyword in method argument and in generated IL compiler adds metadata to extension method as in following. ([System.Core]System.Runtime.CompilerServices.ExtensionAttribute)

.class public auto ansi abstract sealed beforefieldinit System.ObjectExtensions
    extends [mscorlib]System.Object
{
    .custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
        01 00 00 00
    )
    // Methods
    .method public hidebysig static 
        string ToJson (
            object obj
        ) cil managed 
    {
        .custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x208c
        // Code size 12 (0xc)
        .maxstack 1
        .locals init (
            [0] string CS$1$0000
        )

        IL_0000: nop
        IL_0001: ldarg.0
        IL_0002: call string [Newtonsoft.Json]Newtonsoft.Json.JsonConvert::SerializeObject(object)
        IL_0007: stloc.0
        IL_0008: br.s IL_000a

        IL_000a: ldloc.0
        IL_000b: ret
    } // end of method ObjectExtensions::ToJson

} // end of class System.ObjectExtensions

This essentially enables external code to detect that the original codebase has used the method as an extension method by using reflection. Otherwise there is no way of telling since the IL is just static method call This is exactly what reflection based tools like ILSpy does when decompiling IL. Current version of it correctly decompile the IL to extension method format which is easy with this compiler generated attributes. However this was not the case with early version of TelericDecompile that I had previously and it just shows extension methods as static method calls when decompiled to source code.

Advertisements
 
Leave a comment

Posted by on October 18, 2014 in .NET, C#

 

Tags: ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: