33

我通常知道“隐式捕获的关闭”是什么意思,但是,今天我遇到了以下情况:

public static void Foo (Bar bar, Action<int> a, Action<int> b, int c)
{
    bar.RegisterHandler(x => a(c)); // Implicitly captured closure: b
    bar.RegisterHandler(x => b(c)); // Implicitly captured closure: a
}

为什么我还要隐含地捕捉其他动作?如果我评论这两行中的任何一行,另一行不会给我警告。有人知道 ReSharper 警告我有什么危险吗?

编辑:ReSharper 8.0.1

4

3 回答 3

35

这里的问题是,当你关闭一个变量时,幕后发生的事情是编译器创建一个新的未命名类型,为该类型中的每个关闭的变量提供一个实例字段,为每个匿名提供一个方法该代码块中的方法,然后传递该对象的单个实例

这意味着第一个委托的生命周期使该闭包对象保持活动状态,并且b除了a内部之外,它还具有对 object 的引用,反之亦然。

现在在你的情况下,这不是问题,因为它Action不是特别占用内存的东西,所以让它存活更长时间并不是真正的问题。

理论上,C# 团队可以确保在这种特殊情况下,可以为同一块中的每个闭包创建一个新的未命名类型,但他们选择不这样做,因为这会使常见情况变得更糟。

于 2013-09-17T20:34:16.697 回答
0

还有一个警告,我对此很生气:

List<List<string>> allowed = AllowedSCACSwaps;
foreach (List<string> c in allowed.Where(c => c.Contains(scac)))
{
    csc = openCycles.FirstOrDefault(icsc => (icsc.CustomerCode == customerCode) && c.Contains(icsc.SCAC));
    if (null != csc)
    {
        return csc;
    }
}

说“客户代码的隐式关闭”

string cc = customerCode.ToUpperInvariant();
string sc = scac.ToUpperInvariant();    List<List<string>> allowed = AllowedSCACSwaps;
    foreach (List<string> c in allowed.Where(c => c.Contains(sc)))
    {
        csc = openCycles.FirstOrDefault(icsc => (icsc.CustomerCode == cc) && c.Contains(icsc.SCAC));
        if (null != csc)
        {
            return csc;
        }
    }

没问题。

我发疯的原因?

scac 和 customerCode 都是传入该方法的字符串。但即使我用 cc 替换了 customerCode,我仍然收到同样的警告。

关闭实际上已经结束了 scac,但 Resharper 误报了它。

于 2014-03-12T01:26:27.403 回答
0

我以前见过这个;它与在 lambda 的生命周期内保留的变量有关,因此如果它们很大,则会产生内存压力。

于 2013-09-17T20:33:53.513 回答