c# - studio - Resharper: cierre capturado implícitamente: este
resharper visual studio 2017 full mega (2)
Parece que _response
es un campo en tu clase.
_response
referencia a _response
de lambda capturará this
en el cierre y leerá this._response
cuando se ejecute lambda.
Para evitar esto, puede copiar _response
a una variable local y usar eso en su lugar. Tenga en cuenta que eso hará que use el valor actual de _response
lugar de su valor eventual.
Recibo esta advertencia ("Implicity capture closure: this") de Resharper: ¿significa esto que de alguna manera este código captura todo el objeto envolvente?
internal Timer Timeout = new Timer
{
Enabled = false,
AutoReset = false
};
public Task<Response> ResponseTask
{
get
{
var tcs = new TaskCompletionSource<Response>();
Timeout.Elapsed += (e, a) => tcs.SetException(new TimeoutException("Timeout at " + a.SignalTime));
if (_response != null) tcs.SetResult(_response);
else ResponseHandler += r => tcs.SetResult(_response);
return tcs.Task;
}
}
No estoy seguro de cómo o por qué lo está haciendo, la única variable que debería capturar es TaskCompletionSource, que es intencional. ¿Es esto realmente un problema y cómo voy a resolverlo si lo es?
EDITAR: La advertencia está en el primer lambda (el evento Timeout).
Parece que el problema no es la línea que creo que es.
El problema es que tengo dos lambdas que hacen referencia a campos en el objeto principal: el compilador genera una clase con dos métodos y una referencia a la clase padre ( this
).
Creo que esto sería un problema porque la referencia a this
podría mantenerse en el objeto TaskCompletionSource, evitando que sea GCed. Al menos eso es lo que he encontrado sobre este tema sugiere.
La clase generada se vería así (obviamente, los nombres serán diferentes e impronunciables):
class GeneratedClass {
Request _this;
TaskCompletionSource tcs;
public lambda1 (Object e, ElapsedEventArgs a) {
tcs.SetException(new TimeoutException("Timeout at " + a.SignalTime));
}
public lambda2 () {
tcs.SetResult(_this._response);
}
}
La razón por la que el compilador hace esto es probablemente la eficiencia, supongo, ya que TaskCompletionSource
es utilizado por ambos lambdas; pero ahora, siempre que se haga referencia a una referencia a una de esas lambdas, también se mantendrá la referencia al objeto Request
.
Sin embargo, todavía no estoy más cerca de descubrir cómo evitar este problema.
EDITAR: Obviamente no pensé en esto cuando lo estaba escribiendo. Resolví el problema cambiando el método de esta manera:
public Task<Response> TaskResponse
{
get
{
var tcs = new TaskCompletionSource<Response>();
Timeout.Elapsed += (e, a) => tcs.SetException(new TimeoutException("Timeout at " + a.SignalTime));
if (_response != null) tcs.SetResult(_response);
else ResponseHandler += tcs.SetResult; //The event passes an object of type Response (derp) which is then assigned to the _response field.
return tcs.Task;
}
}