When to use anonymous methods in C#

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 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 under the hood, so you can make your own decision based on your unique solution.

Background


There are situations anonymous methods are really useful; especially if you have a small operation you want to do in line. 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 programmers 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 affect. What happens to the structure in the background after you compile, is shown in the disassembled 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
<Method>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 one 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 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 (excep some not 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 red Gate'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:). 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 my unique solution:

 
class NonAnonymous
{
   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 the 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.(Collapsed 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 of making the right decision for you unique solution.
Ebook Download
View all
Learn
View all