Pregunta Cierres capturados implícitamente, advertencia de ReSharper


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


32
2017-09-17 20:27


origen


Respuestas:


El problema aquí es que cuando cierras una variable, lo que sucede detrás de escena 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 método anónimo en ese bloque de código y luego pasa un única instancia de ese objeto alrededor.

Esto significa que la vida del primer delegado mantiene vivo ese objeto de cierre y tiene una referencia al objeto b, además de ainternamente y viceversa

Ahora en tu caso, no es un problema, como Action no es algo que requiera mucha memoria, por lo que mantenerlo con vida 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.


35
2017-09-17 20:34



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.


0
2017-09-17 20:33



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.


0
2018-03-12 01:26