为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
心有法竹 2022-11-13 17:32:50
我试图了解编译器支持的委托缓存的边缘情况以避免内存分配。例如,据我了解,此委托被缓存到单个实例并被重用,因为它不会关闭任何局部变量: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为了避免这种情况,我看到了两种选择:使用构造函数:var result = (new Func<int, bool>(x => x % 2 == 0)).Invoke(5);铸造匿名委托:var result = ((Func<int, bool>)(x => x % 2 == 0)).Invoke(5);我假设编译器不会在选项 #1 中缓存委托,但我不确定它是否会在 #2 中缓存。这在任何地方都有记录吗?
查看完整描述

1 回答

?
茅侃侃

TA贡献1842条经验 获得超22个赞

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

事实上,在这两种情况下都可以,而且它们是捆绑在一起的。

来自 ECMA C# 5 规范,第 7.6.10.5 节:

new D(E) 形式的委托创建表达式(其中 D 是委托类型,E 是表达式)的绑定时处理包括以下步骤:

  • ...

  • 如果 E 是匿名函数,则委托创建表达式的处理方式与从 E 到 D 的匿名函数转换(第 6.5 节)相同。

  • ...

所以基本上两者的处理方式相同。在这两种情况下,它都可以被缓存。是的,“新并不一定意味着新”是很奇怪的。

为了说明这一点,让我们编写一个非常简单的程序:

using System;


public class Program

{

    public static void Main()

    {

        var func = new Func<int, bool>(x => x % 2 == 0);

    }

}

这是我机器上的方法的 IL Main(诚然是使用 C# 8 预览版编译器构建的,但我希望在一段时间内也是如此):


.method public hidebysig static void  Main() cil managed

{

  .entrypoint

  // Code size       29 (0x1d)

  .maxstack  8

  IL_0000:  ldsfld     class [mscorlib]System.Func`2<int32,bool> Program/'<>c'::'<>9__0_0'

  IL_0005:  brtrue.s   IL_001c

  IL_0007:  ldsfld     class Program/'<>c' Program/'<>c'::'<>9'

  IL_000c:  ldftn      instance bool Program/'<>c'::'<Main>b__0_0'(int32)

  IL_0012:  newobj     instance void class [mscorlib]System.Func`2<int32,bool>::.ctor(object,

                                                                                      native int)

  IL_0017:  stsfld     class [mscorlib]System.Func`2<int32,bool> Program/'<>c'::'<>9__0_0'

  IL_001c:  ret

} // end of method Program::Main

这是有效的:


Func<int, bool> func;

func = cache;

if (func == null)

{

    func = new Func<int, bool>(GeneratedPrivateMethod);

    cache = func;

}


查看完整回答
反对 回复 2022-11-13
  • 1 回答
  • 0 关注
  • 140 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号