c# - 将匿名 lambda 转换为强类型委托(delegate)会禁用编译器缓存吗?

标签 c# lambda delegates

我正在尝试了解编译器支持的委托(delegate)缓存的边缘情况以避免内存分配。

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

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

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

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

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

  1. 使用构造函数:
var result = (new Func<int, bool>(x => x % 2 == 0)).Invoke(5);
  1. 类型转换匿名委托(delegate):
var result = ((Func<int, bool>)(x => x % 2 == 0)).Invoke(5);

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

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

最佳答案

I'm assuming the compiler will not cache the delegate in option #1, but I'm not sure if it will in #2.

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

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

The binding-time processing of a delegate-creation-expression of the form new D(E), where D is a delegate-type and E is an expression, consists of the following steps:

  • ...
  • If E is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (§6.5) from E to D.
  • ...

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

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

using System;

public class Program
{
    public static void Main()
    {
        var func = new Func<int, bool>(x => x % 2 == 0);
    }
}

这是我机器上 Main 方法的 IL(诚然是使用 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;
}

关于c# - 将匿名 lambda 转换为强类型委托(delegate)会禁用编译器缓存吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55366478/

相关文章:

java - 为什么 Java8 flatmap 返回一个 List of List?

c - Vala中如何指定在回调参数之前提供用户数据?

c# - 异步调用 - 是否需要 EndInvoke?

c# - 通用委托(delegate),C# 3.5

c# - C# 中鼠标跟随绘图

c# - asp.net mvc : make RedirectToAction(string, 对象) 到 RedirectToAction<Controller>(x => x.Detail(id))

c# - 使用 NAudio 更改 wav 文件(到 16KHz 和 8bit)

c++ - if-else语句lambda表达式的返回类型推导

c# 查找与 1 年前相同的 "named days"范围

c# - C#中两个数组的相关性