隐式捕获闭包,ReSharper警告

时间:2013-09-17 20:27:56

标签: c# closures resharper

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

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

3 个答案:

答案 0 :(得分:35)

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

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

现在在你的情况下,这不是一个问题,因为Action不是特别记忆密集的东西,所以保持它存活一段时间并不是真正的问题。

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

答案 1 :(得分:0)

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

答案 2 :(得分: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;
    }
}

说&#34;对customerCode进行隐式关闭&#34;

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误报了它。