Tengo el siguiente código:
public double CalculateDailyProjectPullForceMax(DateTime date, string start = null, string end = null)
{
Log("Calculating Daily Pull Force Max...");
var pullForceList = start == null
? _pullForce.Where((t, i) => _date[i] == date).ToList() // implicitly captured closure: end, start
: _pullForce.Where(
(t, i) => _date[i] == date && DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 &&
DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();
_pullForceDailyMax = Math.Round(pullForceList.Max(), 2, MidpointRounding.AwayFromZero);
return _pullForceDailyMax;
}
Ahora, he agregado un comentario en la línea que ReSharper sugiere un cambio. ¿Qué significa o por qué necesitaría ser cambiado?implicitly captured closure: end, start
Respuestas:
La advertencia le dice que las variables
end
ystart
permanecen vivas como cualquiera de las lambdas dentro de este método se mantienen vivas.Echa un vistazo al breve ejemplo
Recibo una advertencia de "Cierre capturado implícitamente: g" en la primera lambda. Me está diciendo que
g
no se puede recolectar basura mientras la primera lambda esté en uso.El compilador genera una clase para ambas expresiones lambda y coloca todas las variables en esa clase que se utilizan en las expresiones lambda.
Así que en mi ejemplo
g
yi
se llevan a cabo en la misma clase para la ejecución de mis delegados. Si seg
trata de un objeto pesado con muchos recursos, el recolector de basura no podría reclamarlo, porque la referencia en esta clase aún está viva mientras esté en uso alguna de las expresiones lambda. Entonces, esta es una pérdida potencial de memoria, y esa es la razón de la advertencia de R #.@splintor Como en C #, los métodos anónimos siempre se almacenan en una clase por método, hay dos formas de evitar esto:
Use un método de instancia en lugar de uno anónimo.
Divide la creación de las expresiones lambda en dos métodos.
fuente
Random
embargo, en el caso anterior, por lo que puedo decir, el comportamiento deseado es en realidad mantener una referencia a la instancia.De acuerdo con Peter Mortensen.
El compilador de C # genera solo un tipo que encapsula todas las variables para todas las expresiones lambda en un método.
Por ejemplo, dado el código fuente:
El compilador genera un tipo similar a:
Y el
Capture
método se compila como:Aunque la segunda lambda no se utiliza
x
, no se puede recolectar basura, ya quex
se compila como una propiedad de la clase generada utilizada en la lambda.fuente
La advertencia es válida y se muestra en métodos que tienen más de una lambda , y capturan valores diferentes .
Cuando se invoca un método que contiene lambdas, se crea una instancia de un objeto generado por el compilador con:
Como ejemplo:
Examine el código generado para esta clase (arreglado un poco):
Tenga en cuenta la instancia de
LambdaHelper
tiendas creadas tantop1
yp2
.Imagina eso:
callable1
mantiene una referencia de larga duración a su argumento,helper.Lambda1
callable2
no mantiene una referencia a su argumento,helper.Lambda2
En esta situación, la referencia a
helper.Lambda1
también hace referencia indirecta a la cadenap2
, y esto significa que el recolector de basura no podrá desasignarla. En el peor de los casos, es una pérdida de memoria / recursos. Alternativamente, puede mantener los objetos vivos más tiempo de lo que se necesita, lo que puede tener un impacto en GC si son promovidos de gen0 a gen1.fuente
p1
decallable2
esta manera:callable2(() => { p2.ToString(); });
- ¿esto todavía no causaría el mismo problema (el recolector de basura no podrá desasignarlo)LambdaHelper
que todavía contendráp1
yp2
?LambdaHelper
arriba) para todas las lambdas dentro del método padre. Entonces, incluso sicallable2
no se usarap1
, compartiría el mismo objeto de captura quecallable1
, y ese objeto de captura haría referencia a ambosp1
yp2
. Tenga en cuenta que esto realmente solo importa para los tipos de referencia, yp1
en este ejemplo es un tipo de valor.Para consultas de Linq a Sql, puede recibir esta advertencia. El alcance de la lambda puede sobrevivir al método debido al hecho de que la consulta a menudo se actualiza después de que el método esté fuera del alcance. Dependiendo de su situación, es posible que desee actualizar los resultados (es decir, a través de .ToList ()) dentro del método para permitir GC en los vars de instancia del método capturados en la lambda L2S.
fuente
Siempre puede descubrir las razones de las sugerencias de R # simplemente haciendo clic en las sugerencias como se muestra a continuación:
Esta pista te dirigirá aquí .
fuente