ReSharper, предупреждающий - доступ к измененному закрытию

Я рассматриваю язык сценариев как что-либо не требование откровенного тяжеловеса, чувствующего, что 'компиляция' ступает. Основная функция с точки зрения программистов: Вы редактируете код и выполняете его сразу же.

Таким образом я расценил бы JavaScript и PHP как языки сценариев, тогда как ActionScript 3 / Flex не действительно.

37
задан Bill the Lizard 15 December 2009 в 15:26
поделиться

1 ответ

Причина предупреждения что внутри цикла вы можете обращаться к изменяющейся переменной. Однако «исправление» на самом деле ничего не делает для вас в этом контексте, не являющемся циклом.

Представьте, что у вас есть цикл FOR, и if находится внутри него, а объявление строки - вне его. В этом случае ошибка будет правильно определять проблему получения ссылки на что-то нестабильное.

Пример того, чего вы не хотите:

string acctStatus

foreach(...)
{
  acctStatus = account.AccountStatus[...].ToString();
  if (!SettableStatuses().Any(status => status == acctStatus))
      acctStatus = ACCOUNTSTATUS.Pending.ToString();
}

Проблема в том, что замыкание захватывает ссылку на acctStatus, но каждая итерация цикла будет изменять это значение. В в том случае было бы лучше:

foreach(...)
{
  string acctStatus = account.AccountStatus[...].ToString();
  if (!SettableStatuses().Any(status => status == acctStatus))
      acctStatus = ACCOUNTSTATUS.Pending.ToString();
}

Поскольку контекст переменной - это цикл, новый экземпляр будет создаваться каждый раз, потому что мы переместили переменную внутрь локального контекста (цикл for).

Рекомендация звучит как ошибка в синтаксическом анализе этого кода Resharper. Однако во многих случаях это серьезная проблема (например, в первом примере, где ссылка изменяется, несмотря на то, что она зафиксирована в замыкании).

Мое практическое правило: в случае сомнений сделайте локальный.

Здесь это реальный пример, который меня укусил:

        menu.MenuItems.Clear();
        HistoryItem[] crumbs = policyTree.Crumbs.GetCrumbs(nodeType);

        for (int i = crumbs.Length - 1; i > -1; i--) //Run through items backwards.
        {
            HistoryItem crumb = crumbs[i];
            NodeType type = nodeType; //Local to capture type.
            MenuItem menuItem = new MenuItem(crumb.MenuText);
            menuItem.Click += (s, e) => NavigateToRecord(crumb.ItemGuid, type);
            menu.MenuItems.Add(menuItem);
        }

Обратите внимание, что я фиксирую тип NodeType local, обратите внимание на nodeType и HistoryItem crumb.ItemGuid, а не crumbs [i] .ItemGuid. Это гарантирует, что в моем закрытии не будет ссылок на элементы, которые будут изменены.

Перед использованием локальных переменных события будут запускаться с текущими значениями, а не с полученными значениями, которые я ожидал.

Рекомендация звучит как ошибка при анализе этого кода Resharper. Однако во многих случаях это серьезная проблема (например, в первом примере, где ссылка изменяется, несмотря на ее фиксацию в закрытии).

Мое практическое правило: в случае сомнений сделайте локальный.

Здесь это реальный пример, который меня укусил:

        menu.MenuItems.Clear();
        HistoryItem[] crumbs = policyTree.Crumbs.GetCrumbs(nodeType);

        for (int i = crumbs.Length - 1; i > -1; i--) //Run through items backwards.
        {
            HistoryItem crumb = crumbs[i];
            NodeType type = nodeType; //Local to capture type.
            MenuItem menuItem = new MenuItem(crumb.MenuText);
            menuItem.Click += (s, e) => NavigateToRecord(crumb.ItemGuid, type);
            menu.MenuItems.Add(menuItem);
        }

Обратите внимание, что я фиксирую тип NodeType local, обратите внимание на nodeType и HistoryItem crumb.ItemGuid, а не crumbs [i] .ItemGuid. Это гарантирует, что в моем закрытии не будет ссылок на элементы, которые будут изменены.

Перед использованием локальных переменных события будут запускаться с текущими значениями, а не с полученными значениями, которые я ожидал.

Рекомендация звучит как ошибка при анализе этого кода Resharper. Однако во многих случаях это серьезная проблема (например, в первом примере, где ссылка изменяется, несмотря на ее фиксацию в закрытии).

Мое практическое правило: в случае сомнений сделайте локальный.

Здесь это реальный пример, который меня укусил:

        menu.MenuItems.Clear();
        HistoryItem[] crumbs = policyTree.Crumbs.GetCrumbs(nodeType);

        for (int i = crumbs.Length - 1; i > -1; i--) //Run through items backwards.
        {
            HistoryItem crumb = crumbs[i];
            NodeType type = nodeType; //Local to capture type.
            MenuItem menuItem = new MenuItem(crumb.MenuText);
            menuItem.Click += (s, e) => NavigateToRecord(crumb.ItemGuid, type);
            menu.MenuItems.Add(menuItem);
        }

Обратите внимание, что я фиксирую тип NodeType local, обратите внимание на nodeType и HistoryItem crumb.ItemGuid, а не crumbs [i] .ItemGuid. Это гарантирует, что в моем закрытии не будет ссылок на элементы, которые будут изменены.

Перед использованием локальных переменных события будут запускаться с текущими значениями, а не с полученными значениями, которые я ожидал.

где ссылка меняется, несмотря на то, что она фиксируется в закрытии).

Мое практическое правило: в случае сомнений делайте локальную.

Вот пример из реального мира, который меня укусил:

        menu.MenuItems.Clear();
        HistoryItem[] crumbs = policyTree.Crumbs.GetCrumbs(nodeType);

        for (int i = crumbs.Length - 1; i > -1; i--) //Run through items backwards.
        {
            HistoryItem crumb = crumbs[i];
            NodeType type = nodeType; //Local to capture type.
            MenuItem menuItem = new MenuItem(crumb.MenuText);
            menuItem.Click += (s, e) => NavigateToRecord(crumb.ItemGuid, type);
            menu.MenuItems.Add(menuItem);
        }

Обратите внимание, что я фиксирую тип NodeType локальный, обратите внимание на nodeType и HistoryItem crumb.ItemGuid, а не crumbs [i] .ItemGuid. Это гарантирует, что в моем закрытии не будет ссылок на элементы, которые будут изменены.

Перед использованием локальных переменных события будут запускаться с текущими значениями, а не с полученными значениями, которые я ожидал.

где ссылка меняется, несмотря на то, что она фиксируется в закрытии).

Мое практическое правило: в случае сомнений делайте локальную.

Вот пример из реального мира, который меня укусил:

        menu.MenuItems.Clear();
        HistoryItem[] crumbs = policyTree.Crumbs.GetCrumbs(nodeType);

        for (int i = crumbs.Length - 1; i > -1; i--) //Run through items backwards.
        {
            HistoryItem crumb = crumbs[i];
            NodeType type = nodeType; //Local to capture type.
            MenuItem menuItem = new MenuItem(crumb.MenuText);
            menuItem.Click += (s, e) => NavigateToRecord(crumb.ItemGuid, type);
            menu.MenuItems.Add(menuItem);
        }

Обратите внимание, что я фиксирую тип NodeType локальный, обратите внимание на nodeType и HistoryItem crumb.ItemGuid, а не crumbs [i] .ItemGuid. Это гарантирует, что в моем закрытии не будет ссылок на элементы, которые будут изменены.

Перед использованием локальных переменных события будут запускаться с текущими значениями, а не с полученными значениями, которые я ожидал.

события будут запускаться с текущими значениями, а не с полученными значениями, которые я ожидал.

события будут запускаться с текущими значениями, а не с полученными значениями, которые я ожидал.

35
ответ дан 27 November 2019 в 05:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: