October 1, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

The New Lambda Expressions Feature in C# 3.0

  • April 12, 2006
  • By Vipul Patel
  • Send Email »
  • More Articles »

Inside the Intermediate Language (IL)

To get under the hood of the code, fire up ILDASM and select the application. You will see something similar to the screenshot in Figure 1.



Click here for a larger image.

Figure 1: Sample Application in ILDASM

Double-click the AnonMethod function to see the IL generated by the C# compiler:

.method private hidebysig static void AnonMethod(class
   [mscorlib]System.Collections.Generic.List`1<string> list)
   cil managed
{
   // Code size       96 (0x60)
   .maxstack  4
   .locals init ([0] class [mscorlib]System.Collections.Generic.List
                    `1<string> evenNumbers,
                 [1] string evenNumber,
                 [2] valuetype [mscorlib]System.Collections.Generic.List
                     `1/Enumerator<string> CS$5$0000,
                 [3] bool CS$4$0001)
   IL_0000:  nop
   IL_0001:  ldarg.0
   IL_0002:  ldsfld     class [mscorlib]System.Predicate
                        `1<string> LambdaExample.Program::
                        `<>9__CachedAnonymousMethodDelegate1'
   IL_0007:  brtrue.s   IL_001c
   IL_0009:  ldnull
   IL_000a:  ldftn      bool LambdaExample.Program::
                        `<AnonMethod>b__0'(string)
   IL_0010:  newobj     instance void class [mscorlib]System.Predicate
                        `1<string>::.ctor(object, native int)
   IL_0015:  stsfld     class [mscorlib]System.Predicate`1<string>
                        LambdaExample.Program::
                        `<>9__CachedAnonymousMethodDelegate1'
   IL_001a:  br.s       IL_001c
   IL_001c:  ldsfld     class [mscorlib]System.Predicate`1<string>
                        LambdaExample.Program::'<>
                        9__CachedAnonymousMethodDelegate1'
   IL_0021:  callvirt   instance class [mscorlib]System.Collections.
                         Generic.List`1<!0> class [mscorlib]System.
                         Collections.Generic.List`1<string>::
                         FindAll(class [mscorlib]System.Predicate`1<!0>)
   IL_0026:  stloc.0
   IL_0027:  nop
   IL_0028:  ldloc.0
   IL_0029:  callvirt   instance valuetype [mscorlib]System.Collections.
                        Generic.List`1/Enumerator<!0> class
                        [mscorlib]System.Collections.Generic.List`1
                        <string>::GetEnumerator()
   IL_002e:  stloc.2
   .try
   {
      IL_002f:  br.s       IL_0042
      IL_0031:  ldloca.s   CS$5$0000
      IL_0033:  call       instance !0 valuetype [mscorlib]System.
                           Collections.Generic.List`1/Enumerator
                           <string>::get_Current()
      IL_0038:  stloc.1
      IL_0039:  nop
      IL_003a:  ldloc.1
      IL_003b:  call       void [mscorlib]System.Console::
                           WriteLine(string)
      IL_0040:  nop
      IL_0041:  nop
      IL_0042:  ldloca.s   CS$5$0000
      IL_0044:  call       instance bool valuetype [mscorlib]System.
                           Collections.Generic.List`1/Enumerator
                           <string>::MoveNext()
      IL_0049:  stloc.3
      IL_004a:  ldloc.3
      IL_004b:  brtrue.s   IL_0031
      IL_004d:  leave.s    IL_005e
   }  // end .try
   finally
   {
      IL_004f:  ldloca.s   CS$5$0000
      IL_0051:  constrained. valuetype [mscorlib]System.Collections.
                Generic.List`1/Enumerator<string>
      IL_0057:  callvirt   instance void [mscorlib]System.
                IDisposable::Dispose()
      IL_005c:  nop
      IL_005d:  endfinally
   }  // end handler
   IL_005e:  nop
   IL_005f:  ret
}    // end of method Program::AnonMethod

Now see the IL generated by the LambdaExample function. It is strikingly similar to the code generated by the LambdaExample method:

.method private hidebysig static void  LambdaExample(class [mscorlib]System.Collections.Generic.List`1<string> list) cil managed
{
  // Code size       96 (0x60)
  .maxstack  4
  .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<string> evenNumbers,
           [1] string i,
           [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> CS$5$0000,
           [3] bool CS$4$0001)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldsfld     class [mscorlib]System.Predicate`1<string> LambdaExample.Program::'<>9__CachedAnonymousMethodDelegate5'
  IL_0007:  brtrue.s   IL_001c
  IL_0009:  ldnull
  IL_000a:  ldftn      bool LambdaExample.Program::'<LambdaExample>b__4'(string)
  IL_0010:  newobj     instance void class [mscorlib]System.Predicate`1<string>::.ctor(object,
                                                                                       native int)
  IL_0015:  stsfld     class [mscorlib]System.Predicate`1<string> LambdaExample.Program::'<>9__CachedAnonymousMethodDelegate5'
  IL_001a:  br.s       IL_001c
  IL_001c:  ldsfld     class [mscorlib]System.Predicate`1<string> LambdaExample.Program::'<>9__CachedAnonymousMethodDelegate5'
  IL_0021:  callvirt   instance class [mscorlib]System.Collections.Generic.List`1<!0> class [mscorlib]System.Collections.Generic.List`1<string>::FindAll(class [mscorlib]System.Predicate`1<!0>)
  IL_0026:  stloc.0
  IL_0027:  nop
  IL_0028:  ldloc.0
  IL_0029:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
  IL_002e:  stloc.2
  .try
  {
    IL_002f:  br.s       IL_0042
    IL_0031:  ldloca.s   CS$5$0000
    IL_0033:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current()
    IL_0038:  stloc.1
    IL_0039:  nop
    IL_003a:  ldloc.1
    IL_003b:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0040:  nop
    IL_0041:  nop
    IL_0042:  ldloca.s   CS$5$0000
    IL_0044:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext()
    IL_0049:  stloc.3
    IL_004a:  ldloc.3
    IL_004b:  brtrue.s   IL_0031
    IL_004d:  leave.s    IL_005e
  }  // end .try
  finally
  {
    IL_004f:  ldloca.s   CS$5$0000
    IL_0051:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
    IL_0057:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_005c:  nop
    IL_005d:  endfinally
  }  // end handler
  IL_005e:  nop
  IL_005f:  ret
} // end of method Program::LambdaExample

From the code listing above, you can deduce that the anonymous method and the lambda expression essentially compile to the same IL internally. Hence, their executions are similar.

Lambda Expressions with Multiple Parameters

Lambda expressions can take up multiple parameters. For example, say you have a Dictionary containing the information in Table 1.

Clothing Type Count
Shirts 15
Jeans 12
Shoes 9
Pajamas 9

Table 1: Information in Dictionary

If you have an anonymous method (FilterBy) to filter the dictionary by key and value, you can call that anonymous method through lambda expressions passing multiple parameters. The accompanying source code has the implementation of FilterBy:

var ClothesListShortage = clothesList.FilterBy((string name, int count)
   => name == "Shoes" && count < 10);

Simpler Syntax

Lambda expressions provide a simple way to write inline code blocks where delegates are expected. Their behavior is strikingly similar to anonymous methods. In fact, they are syntactic sugar in terms of syntax. They can take multiple parameters, explicit or implicit.

Download the Code

You can download the code that accompanies the article here.

About the Author

Vipul Patel is a Microsoft MVP (two years in a row) in Visual C# and currently works at Microsoft through Volt Information Sciences. He specializes in C# and deployment issues. You can reach him at Vipul_d_patel@hotmail.com.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel