c# - Advertencia de ReSharper: acceso al cierre modificado
warnings (1)
El motivo de la advertencia es que dentro de un ciclo puede estar accediendo a una variable que está cambiando. Sin embargo, la "solución" no está realmente haciendo nada por ti en este contexto sin bucle.
Imagine que tenía un bucle FOR y el if estaba dentro y la declaración de cadena estaba fuera de él. En ese caso, el error sería identificar correctamente el problema de obtener una referencia a algo inestable.
Un ejemplo de lo que no quieres:
string acctStatus
foreach(...)
{
acctStatus = account.AccountStatus[...].ToString();
if (!SettableStatuses().Any(status => status == acctStatus))
acctStatus = ACCOUNTSTATUS.Pending.ToString();
}
El problema es que el cierre tomará una referencia a acctStatus, pero cada iteración de bucle cambiará ese valor. En ese caso, sería mejor:
foreach(...)
{
string acctStatus = account.AccountStatus[...].ToString();
if (!SettableStatuses().Any(status => status == acctStatus))
acctStatus = ACCOUNTSTATUS.Pending.ToString();
}
Como el contexto de la variable es el bucle, se creará una nueva instancia cada vez porque hemos movido la variable dentro del contexto local (el bucle for).
La recomendación suena como un error en el análisis de Resharper de ese código. Sin embargo, en muchos casos esto es una preocupación válida (como el primer ejemplo, donde la referencia está cambiando a pesar de su captura en un cierre).
Mi regla de oro es que, en caso de duda, hacer un local.
Aquí hay un ejemplo del mundo real que me mordió:
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);
}
Tenga en cuenta que capturo el NodeType type local, note nodeType e HistoryItem migmb.ItemGuid, no migmbs [i] .ItemGuid. Esto asegura que mi cierre no tendrá referencias a elementos que cambiarán.
Antes de usar los locales, los eventos se activan con los valores actuales, no con los valores capturados que esperaba.
Tengo el siguiente código:
string acctStatus = account.AccountStatus.ToString();
if (!SettableStatuses().Any(status => status == acctStatus))
acctStatus = ACCOUNTSTATUS.Pending.ToString();
Tenga en cuenta que account.AccountStatus es una enumeración de tipo ACCOUNTSTATUS. En la segunda línea, ReSharper me está dando la advertencia "Acceso al cierre modificado" para acctStatus. Cuando hago la operación recomendada, Copiar a la variable local , modifica el código a lo siguiente:
string acctStatus = realAccount.AccountStatus.ToString();
string s = acctStatus;
if (!SettableStatuses().Any(status => status == s))
acctStatus = ACCOUNTSTATUS.Pending.ToString();
¿Por qué es esto mejor o preferible a lo que tenía originalmente?
EDITAR
También recomienda ajustar la variable local en matriz , lo que produce:
string[] acctStatus = {realAccount.AccountStatus.ToString()};
if (!SettableStatuses().Any(status => status == acctStatus[0]))
acctStatus[0] = ACCOUNTSTATUS.Pending.ToString();
Esto me parece francamente loco.