为什么一些C#lambdaexpression式编译为静态方法?

正如你在下面的代码中看到的,我已经声明了一个Action<>对象作为variables。

有人请让我知道为什么这个行动方法委托行为像一个静态的方法?

为什么在下面的代码中返回true

码:

 public static void Main(string[] args) { Action<string> actionMethod = s => { Console.WriteLine("My Name is " + s); }; Console.WriteLine(actionMethod.Method.IsStatic); Console.Read(); } 

输出:

示例输出示例

这很可能是因为没有closures,例如:

 int age = 25; Action<string> withClosure = s => Console.WriteLine("My name is {0} and I am {1} years old", s, age); Action<string> withoutClosure = s => Console.WriteLine("My name is {0}", s); Console.WriteLine(withClosure.Method.IsStatic); Console.WriteLine(withoutClosure.Method.IsStatic); 

这将为withClosure输出falsewithClosure输出true

当你使用一个lambdaexpression式时,编译器会创build一个小类来包含你的方法,这将被编译成如下所示(实际的实现很可能会略有不同):

 private class <Main>b__0 { public int age; public void withClosure(string s) { Console.WriteLine("My name is {0} and I am {1} years old", s, age) } } private static class <Main>b__1 { public static void withoutClosure(string s) { Console.WriteLine("My name is {0}", s) } } public static void Main() { var b__0 = new <Main>b__0(); b__0.age = 25; Action<string> withClosure = b__0.withClosure; Action<string> withoutClosure = <Main>b__1.withoutClosure; Console.WriteLine(withClosure.Method.IsStatic); Console.WriteLine(withoutClosure.Method.IsStatic); } 

您可以看到由此产生的Action<string>实例实际上指向这些生成的类上的方法。

“行动方法”是静态的,只是作为实施的一个副作用。 这是一个没有捕获variables的匿名方法。 由于没有捕获的variables,所以该方法没有一般的局部variables的生命期要求。 如果它引用了其他局部variables,则其生命周期延伸到其他variables的生命周期(参见C#5.0规范中的第L.1.7节“ 局部variables ”和第N.15.5.1节“ 捕获的外部variables” )。

请注意,C#规范仅讨论将匿名方法转换为“expression式树”,而不是“匿名类”。 虽然expression式树可以表示为附加的C#类,例如,在Microsoft编译器中,但不需要此实现(如C#5.0规范中第M.5.3节所述)。 因此,匿名函数是否是静态的是不确定的。 此外,第K.6节在expression树的细节方面还有很大的空缺。

委托caching行为在Roslyn中进行了更改。 如前所述,任何不捕获variables的lambdaexpression式在调用位置被编译成static方法。 Roslyn改变了这种行为。 现在,任何捕获variables的lambda都被转换成一个显示类:

鉴于这个例子:

 public class C { public void M() { var x = 5; Action<int> action = y => Console.WriteLine(y); } } 

本地编译器输出:

 public class C { [CompilerGenerated] private static Action<int> CS$<>9__CachedAnonymousMethodDelegate1; public void M() { if (C.CS$<>9__CachedAnonymousMethodDelegate1 == null) { C.CS$<>9__CachedAnonymousMethodDelegate1 = new Action<int>(C.<M>b__0); } Action<int> arg_1D_0 = C.CS$<>9__CachedAnonymousMethodDelegate1; } [CompilerGenerated] private static void <M>b__0(int y) { Console.WriteLine(y); } } 

罗斯林:

 public class C { [CompilerGenerated] private sealed class <>c__DisplayClass0 { public static readonly C.<>c__DisplayClass0 CS$<>9__inst; public static Action<int> CS$<>9__CachedAnonymousMethodDelegate2; static <>c__DisplayClass0() { // Note: this type is marked as 'beforefieldinit'. C.<>c__DisplayClass0.CS$<>9__inst = new C.<>c__DisplayClass0(); } internal void <M>b__1(int y) { Console.WriteLine(y); } } public void M() { Action<int> arg_22_0; if (arg_22_0 = C. <>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 == null) { C.<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 = new Action<int>(C.<>c__DisplayClass0.CS$<>9__inst.<M>b__1); } } } 

Roslyn中委托caching行为的变化谈到了为什么做这个改变。

该方法没有closures,也引用了一个静态方法本身(Console.WriteLine),所以我希望它是静态的。 该方法将为一个闭包声明一个封闭的匿名types,但是在这个例子中它不是必需的。

从C#6开始,这将始终默认为实例方法,并且永远不会是静态的(所以actionMethod.Method.IsStatic将始终为false)。

在这里看到: 为什么没有捕获的lambda从C#5中的静态变为C#6中的实例方法?

在这里: 差异在CSC和Roslyn编译器的静态lambdaexpression式评估?