Eu tenho o seguinte 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;
}
Agora, adicionamos um comentário na linha que o ReSharper está sugerindo uma mudança. O que significa ou por que precisaria ser alterado?implicitly captured closure: end, start
Respostas:
O aviso informa que as variáveis
end
estart
permanecer vivo como qualquer um dos lambdas dentro esta estadia método vivo.Dê uma olhada no pequeno exemplo
Recebo um aviso "Fechamento implicitamente capturado: g" no primeiro lambda. Está me dizendo que
g
não pode ser coletado o lixo enquanto o primeiro lambda estiver em uso.O compilador gera uma classe para ambas as expressões lambda e coloca todas as variáveis nessa classe que são usadas nas expressões lambda.
Então, no meu exemplo
g
ei
são realizadas na mesma classe para execução dos meus delegados. Seg
for um objeto pesado com muitos recursos deixados para trás, o coletor de lixo não pôde recuperá-lo, porque a referência nesta classe ainda está ativa enquanto alguma das expressões lambda estiver em uso. Portanto, esse é um vazamento de memória em potencial e esse é o motivo do aviso de R #.@ splintor Como em C #, os métodos anônimos são sempre armazenados em uma classe por método, existem duas maneiras de evitar isso:
Use um método de instância em vez de um método anônimo.
Divida a criação das expressões lambda em dois métodos.
fonte
Random
instância.Concordou com Peter Mortensen.
O compilador C # gera apenas um tipo que encapsula todas as variáveis para todas as expressões lambda em um método.
Por exemplo, dado o código fonte:
O compilador gera um tipo parecido com:
E o
Capture
método é compilado como:Embora o segundo lambda não use
x
, ele não pode ser coletado como lixo, poisx
é compilado como uma propriedade da classe gerada usada no lambda.fonte
O aviso é válido e exibido em métodos que possuem mais de um lambda e eles capturam valores diferentes .
Quando um método que contém lambdas é chamado, um objeto gerado pelo compilador é instanciado com:
Como um exemplo:
Examine o código gerado para esta classe (arrumado um pouco):
Observe a instância de
LambdaHelper
lojas criadas, tantop1
ep2
.Imagine isso:
callable1
mantém uma referência duradoura ao seu argumento,helper.Lambda1
callable2
não mantém uma referência ao seu argumento,helper.Lambda2
Nessa situação, a referência
helper.Lambda1
também referencia indiretamente a cadeia de caracteresp2
e isso significa que o coletor de lixo não poderá desalocá-la. Na pior das hipóteses, é um vazamento de memória / recursos. Como alternativa, ele pode manter o (s) objeto (s) ativo (s) por mais tempo do que o necessário, o que pode afetar o GC se eles forem promovidos do gen0 para o gen1.fonte
p1
decallable2
como isto:callable2(() => { p2.ToString(); });
- que ainda não esta causar o mesmo problema (coletor de lixo não será capaz de desalocar-lo) comoLambdaHelper
ainda irá conterp1
ep2
?LambdaHelper
acima) para todas as lambdas no método pai. Portanto, mesmo quecallable2
não fosse utilizadop1
, ele compartilharia o mesmo objeto de captura quecallable1
, e esse objeto de captura faria referência a ambosp1
ep2
. Observe que isso realmente importa apenas para tipos de referência ep1
, neste exemplo, é um tipo de valor.Para consultas de Linq para Sql, você pode receber este aviso. O escopo do lambda pode sobreviver ao método devido ao fato de que a consulta geralmente é atualizada depois que o método está fora do escopo. Dependendo da sua situação, convém atualizar os resultados (por exemplo, via .ToList ()) dentro do método para permitir o GC nos vars de instância do método capturados no lambda L2S.
fonte
Você sempre pode descobrir algumas razões para sugerir o R # clicando nas dicas, como mostrado abaixo:
Esta dica irá direcioná-lo aqui .
fonte