在Roslyn中委派caching行为的变化

给出以下代码:

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

使用VS2013,.NET 4.5。 在查看反编译的代码时,我们可以看到编译器正在caching呼叫站点的代理:

 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); } } 

查看在Roslyn中反编译的代码(使用TryRoslyn ),得到以下输出:

 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); } } } 

现在我们可以看到代理现在被提升到了C一个私有类,这是一个类似于我们在closures实例variables/字段(闭包)时看到的行为。

我知道这是一个实现细节,在任何时候都可能会发生变化。

不过我还想知道,将代理提升到一个新的类中并将其caching在caching中的简单方法是什么?

编辑:

这个问题谈到了这里所提到的同样的行为。

是。 最重要的部分是,包含lambda实现的方法现在是一个实例方法。

您可以看到一个委托人作为一个中间人通过Invoke接收一个实例调用,并根据实现方法的调用约定来调度该调用。

请注意,有平台的ABI要求,指定如何传递参数,如何返回结果,通过寄存器传递哪些参数,以及在哪些参数中传递“this”等等。 违反这些规则可能会对依赖堆栈的工具(如debugging器)产生不良影响。

现在,如果实现方法是实例方法,那么委托内部唯一需要发生的事情就是将“this”(它是Invoke时的委托实例)修补为封闭的Target对象。 在这一点上,因为一切都已经到了,代表可以直接跳到实现方法体。 在许多情况下,如果实现方法是一个静态方法,那么工作量明显会less得多。

不过我还想知道,将代理提升到一个新的类中并将其caching在caching中的简单方法是什么?

你错过了另外一个非常重要的细节 – 现在是一个实例方法。 我相信这是关键。 IIRC,发现调用一个实例方法“支持”的委托比调用一个由静态方法支持的委托更快 – 这是更改背后的动机。

这是所有的传言,在CodeMash上花费时间与Dustin Campbell和Kevin Pilch-Bisson(都来自Roslyn团队)呆呆地记得,但是根据你所展示的代码,这是有道理的。

(我没有validation自己的性能差异,这听起来像是倒退了…但CLR内部可以这样搞笑…)