Click here to Skip to main content
Click here to Skip to main content

Under the hood of anonymous methods in C#

, 24 Jan 2011
Rate this:
Please Sign up or sign in to vote.
Introduction On this post I’ll help you to make better decisions on using C# anonymous methods. We all have our favorite or known ways to program certain solutions. But I believe that providing the right solution for the problem requires us to free our mind of all biases and think in the context of

Introduction

In this post, I’ll help you make better decisions on using C# anonymous methods. We all have our favorite or known ways to program certain solutions. But I believe that providing the right solution for the problem requires us to free our mind of all biases and think in the context of the problem. Every feature, including GOTO, has a place in this endless solution universe, therefore I’m not telling what not to use, I’m just showing what goes under the hood, so you can make your own decision based on your unique solution.

Background

There are situations where anonymous methods are really useful, especially if you have a small operation you want to do inline. Another point is that you loose on readability and testability: two important qualities of enterprise software. In smaller teams or developer owned projects, these qualities are sometimes omitted. (Nothing bad with that, as I said: there is a place for every feature). In bigger teams, especially if you have to review or continue another programmer’s code, it is really hard to read a line with complex inline code. I faced this problem many times on code review and code ownership changes.

So, let me show you what is going on under the hood, and you can make your own decision:

class Anonymous
{
	public void Method()
	{
		bool test = true;
		Action a = ()=> test = false;
	}
}

Figure – 1

In the example, I used the anonymous method on an Action to simplify the disassembled IL code. The code looks very straightforward and simple to write; there is only one delegate which captures the boolean variable test and sets the value to false. I kept the code simple to show the structural changes. There is even no call to the method; structurally, it does not have any effect. What happens to the structure in the background after you compile is shown in the disassemled MSIL code below (collapsed IL code by purpose; to point to the structure):

.class private auto ansi beforefieldinit Anonymous
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

    .method public hidebysig instance void Method() cil managed
    {
    }

    .class auto ansi sealed nested private beforefieldinit <>c__DisplayClass1
        extends [mscorlib]System.Object
    {
        .custom instance void [mscorlib]
           System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
        .method public hidebysig specialname rtspecialname 
                instance void .ctor() cil managed
        {
        }

        .method public hidebysig instance void b__0() cil managed
        {
        }

        .field public bool test

    }
}

Figure – 2

As you can see, a private sealed nested class named c_DisplayClass1 is created with a method named b__0 for our anonymous method. In the collapsed code, our original Method method is modified in a way to create a new instance of c_DisplayClass1 to call the b__0 method. For those who are new to IL, I manually assembled it into the C# code below:

class ILAssembled
{
	public void Method()
	{
		nested nt = new nested();
		nt.test = true;
	}

	private sealed class nested
	{
		public bool test;

		public void MethodNested()
		{
			test = false;
		}
	}
}

Figure – 3

The compiled IL code of the C# code above is exactly the same (except for some not so important small changes). It is important to know that this IL result is for the code above. In fact, if I would move the local variable test to an instance variable, a method would be created instead of a nested class. Therefore, it is always safer to take a look at the disassembled IL code. My favorite tool is RedGate’s .NET Reflector, which can disassemble into many languages. Another big advantage of looking into the post compiled code is to study .NET Framework namespaces and learn good practices.

Let’s go back to our code. It does not mean that you could write the code in Figure-3 instead of in Figure-1 and save some compile time Smile | :) . The point is that the magic is in the compiler in exchange of testability, readability, and maybe some performance, because you end up with a nested class instead of a method.

Instead, if I would write the code below, I would gain all the qualities I was looking for in my unique solution:

public void Method()
{
	bool test = true;
	MyAction(test);
}
private void MyAction(bool test)
{
	test = false;
}

Figure – 4

As you can see, I created a method named MyAction to implement the functionality. Now I can create a unit test to test MyAction, and my colleagues can also understand the code at first look. It is really important to understand the code at first look if you are reviewing tens of classes; encrypting variable and method names, over using implicit type var, and over using anonymous methods double or triple the review time.

For clarity, I also provided below the disassembled IL code structure of Figure 4 (xollapsed IL code by purpose; to point to the structure):

.class private auto ansi beforefieldinit NonAnonymous
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

    .method public hidebysig instance void Method() cil managed
    {
    }

    .method private hidebysig instance void MyAction(bool test) cil managed
    {
    }

}

Figure – 5

As you can see, there is no nested class declared to run the anonymous method.

Conclusion

I believe knowing what you are using is the key to making the right decision for your unique solution.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Adnan Boz

United States United States
I am an MCAD, MCSD, MCTS, MCPD, MCT and Certified CUDA Programmer.
You can find more technical articles on my blog at http://www.adnanboz.com.

Comments and Discussions

 
GeneralMy vote of 5 Pinmemberfdkjhfds1-Apr-11 11:17 
GeneralMy vote of 4 PinmemberKong-Chang Jie24-Jan-11 11:16 
好文章
GeneralRe: My vote of 4 PinmemberAdnan Boz22-Feb-11 7:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140709.1 | Last Updated 24 Jan 2011
Article Copyright 2011 by Adnan Boz
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid