Доступ к измененному закрытию ... но почему? - PullRequest
5 голосов
/ 22 октября 2010

Увидел несколько подобных вопросов здесь, но ни один из них, казалось, не был моей проблемой ...

Я понимаю (или думал, что понял) концепцию закрытия и понимаю, на что может заставить Жарбер жаловатьсядоступ к измененному закрытию, но в приведенном ниже коде я не понимаю, как нарушаю закрытие.

Поскольку primaryApps объявлено в контексте цикла for, primary не изменится, пока я обрабатываю primaryApps.Если бы я объявил primaryApps вне цикла for, то, безусловно, у меня есть проблемы с закрытием.Но почему в приведенном ниже коде?

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 ]

10 голосов
/ 22 октября 2010

Проблема заключается в следующем операторе

Поскольку primaryApps объявлен в контексте цикла for, основной не изменится, пока я обрабатываю primaryApps.

Resharper просто не может на 100% проверить это.Лямбда, которая ссылается на замыкание, передается в функцию вне контекста этого цикла: метод AppPrimaries.Select.Эта функция может сама сохранять результирующее выражение делегата, выполнять его позже и запускать непосредственно при захвате вопроса о переменной итерации.

Надлежащее определение того, возможно ли это, является довольно сложным делом и, честно говоря, не стоит затраченных усилий.Вместо этого ReSharper выбирает безопасный маршрут и предупреждает о потенциально опасном захвате переменной итерации.

8 голосов
/ 22 октября 2010

Поскольку primaryApps объявляется в контексте цикла for, primary не изменится, пока я обрабатываю primaryApps.Если бы я объявил primaryApps вне цикла for, то, безусловно, у меня есть проблемы с закрытием.Но почему в приведенном ниже коде?

Джаред прав;Чтобы продемонстрировать, почему ваш вывод не следует логически из вашей предпосылки, давайте создадим программу, которая объявляет primaryApps в контексте цикла for, и все еще страдает от проблемы с захваченной переменной цикла.Это достаточно просто сделать.

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 не скрывает селектор на потом;на самом деле это именно то, что все они делают .Как Решарпер должен знать, что они случайно спрятали его в месте, которое не будет доступно позже?

1 голос
/ 22 октября 2010

Насколько я знаю, Resharper генерирует предупреждение каждый раз, когда вы обращаетесь к переменной foreach, даже если она не вызывает закрытия.

0 голосов
/ 22 октября 2010

Да, это просто предупреждение, Посмотрите : http://devnet.jetbrains.net/thread/273042

...