c# - Cierres capturados implícitamente, advertencia de ReSharper
closures (3)
El problema aquí es que cuando cierras una variable, lo que ocurre detrás de las escenas es que el compilador crea un nuevo tipo sin nombre, le da a ese tipo un campo de instancia para cada variable que está cerrada en ese bloque , le da un método para cada anónimo método en ese bloque de código y luego pasa una instancia única de ese objeto.
Esto significa que la vida del primer delegado mantiene vivo ese objeto de cierre, y tiene una referencia al objeto b
, además de a, internamente y viceversa.
Ahora, en su caso, no es un problema, ya que una Action
no es particularmente intensiva en memoria, por lo que mantenerla viva un poco más no es realmente un problema.
El equipo de C # podría, en teoría, haberse asegurado de que en este caso particular se podría crear un nuevo tipo sin nombre para cada cierre en el mismo bloque, pero ellos eligieron no hacerlo ya que empeora el caso común.
Normalmente sé lo que significa "cierre capturado implícitamente", sin embargo, hoy me encontré con la siguiente situación:
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
}
¿Por qué estoy capturando implícitamente la otra acción también? Si comento cualquiera de las dos líneas, la otra no me da la advertencia. ¿Alguien sabe de qué peligro me está advirtiendo ReSharper?
Editar: ReSharper 8.0.1
He visto esto antes; tiene que ver con las variables que se mantienen durante la vida útil de la lambda, por lo que si son grandes puede crear presión de memoria.
Y una advertencia, me estaba volviendo loco por esto:
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;
}
}
diciendo "cierre implícito para customerCode"
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;
}
}
Está bien.
¿Por qué me estaba volviendo loco?
scac y customerCode son ambas cadenas pasadas al método. Pero incluso cuando reemplacé customerCode con cc, seguí recibiendo la misma advertencia.
El cierre fue en realidad sobre scac pero Resharper estaba informando mal.