Thursday, April 14, 2011

Anonymous method exposed

In this post, I am going to explain what Anonymous function is and how CLR interprets them.
Anonymous functions were introduced in .NET 2.0. They provide you the in place code block where a delegate object is acceptable.  Anonymous method can reduce the overhead of declaring a function and you can declare them right at the point of the invocation.

    public class AnonymousFunction
    {
        public delegate void delFunc();
        public void Test()
        {
            int i = 4;
            delFunc delFunc = delegate
            {
                i += 1;
                int j = 0;
                if (i > 1)
                {
                    Action<int> del = delegate { j += 1; i += 1; };
                    del(8);
                }
                Console.WriteLine("i: " + i.ToString() + " j: " + j.ToString());
            };
            delFunc();
        }
    }

You can see in the code above that we have used anonymous methods to give implementation to our delegates delFunc and del. The key point to note here is the variable scope within the anonymous method block. An anonymous method has all the variables available to it that your code can access at the point where anonymous method is declared.  This makes it anonymous method even more useful but on the other hand writing anonymous methods all the places can make your code unmanageable as well.

Now the question comes, how compiler interprets them. For compiler any method should have an associated type so it has to be either instance method or static one. Compiler checks what all resources your anonymous method is using and based on take the decision how it needs to be implemented in your MSIL.

Compiler essentially creates a private class for each anonymous method and makes all variables used inside your anonymous method as the member variable of that private class and sets those member variables from outside (invocation point) with the value of same variables declared in the main class.

To get more understanding of it, let’s see what intermediate code compiler will emit for the above mentioned code. I am simplifying the actual compiler code here for your better understanding

private sealed class MyClassForDelFuncAnonymousMethod
{
    // Fields
    public int i;
 
    // Methods
    public void MYDelFuncAnonymousMethod()
    {
        this.i++;
        int j = 0;
        if (this.i > 1)
        {
            MyClassForDelAnonymousMethod oMyClassForDelAnonymousMethod = new MyClassForDelAnonymousMethod();  
oMyClassForDelAnonymousMethod.j = j;
oMyClassForDelAnonymousMethod.oMyClassForDelFuncAnonymousMethod = this;
 
        Action<int> del=  oMyClassForDelAnonymousMethod.MYDelAnonymousMethod(8);
 
        }
        Console.WriteLine("i: " + this.i.ToString() + " j: " + j.ToString());
    }
 
    // Nested Types
    private sealed class MyClassForDelAnonymousMethod
    {
        // Fields
        public AnonymousFunction.MyClassForDelFuncAnonymousMethod oMyClassForDelFuncAnonymousMethod;
        public int j;
 
        // Methods
        public void MYDelAnonymousMethod (int)
        {
            this.j++;
     this.oMyClassForDelFuncAnonymousMethod.i++;
        }
    }
}
 
 
public void Test()
{
    int i = 4;
        MyClassForDelFuncAnonymousMethod oMyClassForDelFuncAnonymousMethod = new MyClassForDelFuncAnonymousMethod();
oMyClassForDelFuncAnonymousMethod.i = i;
        i++;
        k++;
 
        AnonymousFunction.delFunc delFunc = new AnonymousFunction.delFunc(oMyClassForDelFuncAnonymousMethod.MYDelFuncAnonymousMethod)
 
}


No comments:

Post a Comment