获得修改后的封闭......但为什么呢?

时间:2010-10-22 17:35:54

标签: c# linq resharper closures

在这里看到几个类似的问题,但它们似乎都不是我的问题......

我理解(或者我认为我理解)闭包的概念,并理解什么会导致Resharper抱怨访问修改后的闭包,但在下面的代码中我不明白我是如何违反闭包的。

因为在for循环的上下文中声明了primaryApps,所以在我处理primaryprimaryApps不会改变。如果我在for循环之外声明primaryApps,那么绝对,我有封闭问题。但为什么在下面的代码?

var primaries = (from row in openRequestsDataSet.AppPrimaries
                 select row.User).Distinct();

    foreach (string primary in primaries) {

        // Complains because 'primary' is accessing a modified closure
        var primaryApps = openRequestsDataSet.AppPrimaries.Select(x => x.User == primary);

Resharper是不是很聪明,不知道这不是问题,还是有理由关闭是一个问题,我没有看到?

4 个答案:

答案 0 :(得分:10)

问题出在以下声明中

  

因为在for循环的上下文中声明了primaryApps,所以当我处理primaryApps时,primary不会改变。

Resharper根本无法100%验证这一点。引用此处闭包的lambda将传递给此循环上下文之外的函数:AppPrimaries.Select方法。此函数本身可以存储生成的委托表达式,稍后执行它并直接捕获迭代变量问题。

正确地检测这是否可能是一项艰巨的任务,坦率地说不值得付出努力。相反,ReSharper采取安全路线并警告有关捕获迭代变量的潜在危险。

答案 1 :(得分:8)

  

因为在for循环的上下文中声明了primaryApps,所以在我处理primaryApps时,primary不会改变。如果我在for循环之外声明了primaryApps,那么绝对,我有封闭问题。但为什么在下面的代码?

贾里德是对的;为了证明为什么你的结论不遵循你的前提逻辑,让我们创建一个程序,在for循环的上下文中声明primaryApps,仍然受到捕获的循环变量问题的影响。很容易做到这一点。

static class Extensions
{
    public IEnumerable<int> Select(this IEnumerable<int> items, Func<int, bool> selector)
    {
        C.list.Add(selector);
        return System.Enumerable.Select(items, selector);
    }
}

class C
{
    public static List<Func<int, bool>> list = new List<Func<int, bool>>();
    public static void M()
    { 
        int[] primaries = { 10, 20, 30}; 
        int[] secondaries = { 11, 21, 30}; 

        foreach (int primary in primaries) 
        {
            var primaryApps = secondaries.Select(x => x == primary);
            // do something with primaryApps
        }
        C.N();
    }
    public static void N()
    {
        Console.WriteLine(C.list[0](10)); // true or false?
    }
}

声明“primaryApps”的地方完全不相关。唯一相关的是闭包可以在循环中存活,因此有人可能会在以后调用它,错误地期望闭包中捕获的变量被值捕获

Resharper无法知道Select的特定实现不会将选择器藏起来以便以后使用;事实上,这正是所有人的原因。 Resharper怎么会知道他们碰巧把它藏在一个以后无法进入的地方?

答案 2 :(得分:1)

据我所知,Resharper每次访问foreach变量时都会生成警告,即使它实际上没有导致关闭。

答案 3 :(得分:0)

是的,这只是警告, 看: http://devnet.jetbrains.net/thread/273042