Resharper: implicitly committed closure: this

I get this warning ("Implicity capture closed: this") from Resharper: does this mean that somehow this code captures the entire closed object?

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

I'm not sure how and why he does it - the only variable he needs to capture is TaskCompletionSource, which is intentional. This is really a problem and how can I solve it, if so?

EDIT: warning is on first lambda (wait event).

+62
c # resharper
Oct 18 '12 at 11:48
source share
2 answers

It seems that the problem is not what I think.

The problem is that I have two lambdas binding fields in the parent: the compiler generates a class with two methods and a link to the parent class ( this ).

I think this will be a problem because the reference to this could potentially remain in the TaskCompletionSource object, preventing it from being a GCed. At least this is what I found on this issue.

The generated class will look something like this (obviously, the names will be different and unpronounceable):

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

The reason the compiler does this is probably efficiency, I suppose since TaskCompletionSource used as lambdas; but now, while a reference to one of these lambdas still refers to a reference to a Request object, it is also supported.

I am still not closer to figuring out how to avoid this problem.

EDIT: I obviously did not think about it when I wrote. I solved the problem by changing the method as follows:

  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; } } 
+26
Oct 18
source share

It seems like _response is a field in your class.

The _response link to lambda will write this in close and will read this._response when lambda is executed.

To prevent this, you can copy _response to a local variable and use it instead. Note that this will use the current _response value, not its possible value.

+11
Oct 18
source share



All Articles