将匿名 lambda 转换为强类型委托会禁用编译器缓存吗?

我试图了解编译器支持的委托缓存的边缘情况以避免内存分配。

例如,据我了解,此委托被缓存到单个实例并被重用,因为它不会关闭任何局部变量:

int[] set = new [] { 1, 2, 3, 4, 5, 6 };
var subset = set.Where(x => x % 2 == 0);

现在,在某些情况下,我生成的代码可能想直接调用委托,因此匿名方法在 C# 中无效,如下所示:

var result = (x => x % 2 == 0).Invoke(5); // Invalid

为了避免这种情况,我看到了两种选择:

  1. 使用构造函数:

var result = (new Func<int, bool>(x => x % 2 == 0)).Invoke(5);
  1. 铸造匿名委托:

var result = ((Func<int, bool>)(x => x % 2 == 0)).Invoke(5);

我假设编译器不会在选项 #1 中缓存委托,但我不确定它是否会在 #2 中缓存。

这在任何地方都有记录吗?


心有法竹
浏览 141回答 1
1回答

茅侃侃

我假设编译器不会在选项 #1 中缓存委托,但我不确定它是否会在 #2 中缓存。事实上,在这两种情况下都可以,而且它们是捆绑在一起的。来自 ECMA C# 5 规范,第 7.6.10.5 节:new D(E) 形式的委托创建表达式(其中 D 是委托类型,E 是表达式)的绑定时处理包括以下步骤:...如果 E 是匿名函数,则委托创建表达式的处理方式与从 E 到 D 的匿名函数转换(第 6.5 节)相同。...所以基本上两者的处理方式相同。在这两种情况下,它都可以被缓存。是的,“新并不一定意味着新”是很奇怪的。为了说明这一点,让我们编写一个非常简单的程序:using System;public class Program{&nbsp; &nbsp; public static void Main()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var func = new Func<int, bool>(x => x % 2 == 0);&nbsp; &nbsp; }}这是我机器上的方法的 IL Main(诚然是使用 C# 8 预览版编译器构建的,但我希望在一段时间内也是如此):.method public hidebysig static void&nbsp; Main() cil managed{&nbsp; .entrypoint&nbsp; // Code size&nbsp; &nbsp; &nbsp; &nbsp;29 (0x1d)&nbsp; .maxstack&nbsp; 8&nbsp; IL_0000:&nbsp; ldsfld&nbsp; &nbsp; &nbsp;class [mscorlib]System.Func`2<int32,bool> Program/'<>c'::'<>9__0_0'&nbsp; IL_0005:&nbsp; brtrue.s&nbsp; &nbsp;IL_001c&nbsp; IL_0007:&nbsp; ldsfld&nbsp; &nbsp; &nbsp;class Program/'<>c' Program/'<>c'::'<>9'&nbsp; IL_000c:&nbsp; ldftn&nbsp; &nbsp; &nbsp; instance bool Program/'<>c'::'<Main>b__0_0'(int32)&nbsp; IL_0012:&nbsp; newobj&nbsp; &nbsp; &nbsp;instance void class [mscorlib]System.Func`2<int32,bool>::.ctor(object,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; native int)&nbsp; IL_0017:&nbsp; stsfld&nbsp; &nbsp; &nbsp;class [mscorlib]System.Func`2<int32,bool> Program/'<>c'::'<>9__0_0'&nbsp; IL_001c:&nbsp; ret} // end of method Program::Main这是有效的:Func<int, bool> func;func = cache;if (func == null){&nbsp; &nbsp; func = new Func<int, bool>(GeneratedPrivateMethod);&nbsp; &nbsp; cache = func;}
打开App,查看更多内容
随时随地看视频慕课网APP