C# 中的闭包分配

Closure allocations in C#

我已经安装了 Clr 堆分配分析器扩展,在一个项目中我看到了一些我完全不理解的东西,我有一个带有签名的方法

public Task<int> ExecuteAsync(string sql, dynamic param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
    param = SetModificationValuesForGlobalRing(param);
    return _sqlPolicy.ExecuteAsync(async () =>
    {
        int result;
        using (var connection = new SqlConnection(_connectionString))
        {
            await connection.OpenAsync();
            result = await connection.ExecuteAsync(sql, param as object, transaction, commandTimeout, commandType);
        }
        return result;
    });
}

这个工具给我一个关于方法和所有参数的警告

The compiler will emit a class that will hold this as a field to allow capturing of this closure.

我不知道为什么会出现这种情况,是不是因为可选参数?

您必须是:

  1. 从匿名函数中调用此代码,如 lambda。

    • 或-
  2. 在某处使用了yield/await关键字。

当您使用上述任一方法时,C# 必须创建一个闭包来捕获闭包中使用的任何变量,这些变量的原始作用域在您的 lambda 之外(在第一种情况下)或在 之前的用法并且 在 yield/await 之后(在第二种情况下)。

C# 通过在内存 中创建匿名class(在编译时定义)来捕获闭包。然后,它会在该匿名 class 上为其需要保留的每条信息创建一个字段。这可能导致对象实例的生命周期被延长为闭包的生命周期或方法的生命周期 yield/await.

有时生命周期比您不使用 yield/await 或 lambda 时更长。在这种情况下,您可能会注意到内存使用率高于您的预期(因为垃圾收集器不会收集对象实例,直到闭包完全超出范围或包含 yield/await 的方法已完成)。

您看到的警告只是您的工具试图向您解释上述内容,以便您知道预期此行为以及由此导致的内存使用量的潜在增加。