C#中的内联lambda函数创建行为

时间:2014-07-15 20:51:58

标签: c# lambda

如果我有这样的方法

void SomeMethod () {
    Func<A,B> f =  a => /*Some code*/;
    ...
    b = f (a);
}
每次调用f时,

是否都会SomeMethod创建?我的意思是,该行是否需要时间来计算,或者编译器在编译时将某个函数存储在执行时跳过它?

2 个答案:

答案 0 :(得分:5)

考虑这个简单的例子:

static void Main(string[] args)
{
     Test();
     Test();
}
static void Test()
{
     Func<int, int> f = a => a * a;
     int b = f(2);
     Console.WriteLine(b);
}

创建的方法是:

enter image description here

<Test>b__0的IL代码:

.method private hidebysig static int32  '<Test>b__0'(int32 a) cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       8 (0x8)
  .maxstack  2
  .locals init ([0] int32 CS$1$0000)
  IL_0000:  ldarg.0
  IL_0001:  ldarg.0
  IL_0002:  mul
  IL_0003:  stloc.0
  IL_0004:  br.s       IL_0006
  IL_0006:  ldloc.0
  IL_0007:  ret
} // end of method Program::'<Test>b__0'

Test方法的IL代码:

    .method private hidebysig static void  Test() cil managed
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Func`2<int32,int32> f,
           [1] int32 b)
  IL_0000:  nop
  IL_0001:  ldsfld     class [mscorlib]System.Func`2<int32,int32> ConsoleApplication10.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
  IL_0006:  brtrue.s   IL_001b
  IL_0008:  ldnull
  IL_0009:  ldftn      int32 ConsoleApplication10.Program::'<Test>b__0'(int32)
  IL_000f:  newobj     instance void class [mscorlib]System.Func`2<int32,int32>::.ctor(object,
                                                                                       native int)
  IL_0014:  stsfld     class [mscorlib]System.Func`2<int32,int32> ConsoleApplication10.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
  IL_0019:  br.s       IL_001b
  IL_001b:  ldsfld     class [mscorlib]System.Func`2<int32,int32> ConsoleApplication10.Program::'CS$<>9__CachedAnonymousMethodDelegate1'
  IL_0020:  stloc.0
  IL_0021:  ldloc.0
  IL_0022:  ldc.i4.2
  IL_0023:  callvirt   instance !1 class [mscorlib]System.Func`2<int32,int32>::Invoke(!0)
  IL_0028:  stloc.1
  IL_0029:  ldloc.1
  IL_002a:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_002f:  nop
  IL_0030:  ret
} // end of method Program::Test

每次调用Test方法时,都会加载缓存的匿名委托(Func<int,int>),然后调用Invoke方法。

所以答案是,匿名方法(<Test>b__0)只由编译器创建一次,每次调用函数时都不会创建它。

答案 1 :(得分:4)

C#编译器从lambda箭头创建一个普通(非匿名)方法,然后委托f将生成&#34;生成&#34;调用列表上的方法。

每次SomeMethod运行时,都会创建一个Func<,>委托的新实例,它引用普通(但生成的)方法。

就像:

void SomeMethod () {
    Func<A, B> f = StrangeName;
    ...
    b = f(a);
}

static B StrangeName(A a) {
    /*Some code*/
}