Resharper:隐式捕获闭包:这个

我从Resharper那里得到这个警告(“Implicity capture closure:this”):这是否意味着这个代码捕获整个封闭对象?

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; } } 

我不知道如何或为什么这样做 – 它应该捕获的唯一variables是TaskCompletionSource,这是故意的。 这实际上是一个问题,如果它是如何解决它?

编辑:警告是第一个lambda(超时事件)。

看来这个问题不是我认为的问题。

问题是我在父对象中有两个引用字段的lambdas:编译器用两个方法和一个对父类的引用( this )生成一个类。

我认为这将是一个问题,因为这个引用可能会停留在TaskCompletionSource对象中,阻止它被GCed。 至less这就是我在这个问题上发现的结果。

生成的类看起来像这样(显然名称将是不同的和不可发音的):

 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); } } 

编译器这样做的原因可能是效率,我猜想, TaskCompletionSource被两个lambda使用; 但是现在只要引用其中一个lambda仍然被引用,那么对Request对象的引用也会被保留。

尽pipe如此,我仍然没有弄清楚如何避免这个问题。

编辑:我明显没有想到通过这个时候,我正在写它。 我通过改变这样的方法解决了这个问题:

  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; } } 

看起来_response是你class上的一个领域。

引用lambda中的_response会在闭包中捕获this ,并且在lambda执行时读取this._response

为了防止这种情况,您可以将_response复制到一个局部variables,然后使用它。 请注意,这将导致它使用_response当前值而不是其最终值。