C# Resharper:隐式捕获闭包:此
我从Resharper那里得到这个警告(“隐式捕获闭包:this”):这是否意味着这段代码以某种方式捕获了整个封闭对象C# Resharper:隐式捕获闭包:此,c#,.net,resharper,C#,.net,Resharper,我从Resharper那里得到这个警告(“隐式捕获闭包:this”):这是否意味着这段代码以某种方式捕获了整个封闭对象 internal Timer Timeout = new Timer { Enabled = false, AutoReset = false
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;
}
}
内部计时器超时=新计时器
{
启用=错误,
自动重置=错误
};
公共任务响应任务
{
得到
{
var tcs=new TaskCompletionSource();
Timeout.appeated+=(e,a)=>tcs.SetException(新的TimeoutException(“timeat”+a.SignalTime));
如果(_response!=null)tcs.SetResult(_response);
else ResponseHandler+=r=>tcs.SetResult(_response);
返回tcs.Task;
}
}
我不知道它是如何或为什么这样做的——它应该捕获的唯一变量是TaskCompletionSource,这是有意的。这真的是一个问题吗?如果是,我该如何着手解决
编辑:警告出现在第一个lambda上(超时事件)。看起来
\u response
是类中的一个字段
从lambda中引用\u响应
将在闭包中捕获此
,并在lambda执行时读取此。\u响应
为了防止出现这种情况,您可以将
\u response
复制到局部变量,然后使用它。请注意,这将导致它使用\u response的当前值,而不是其最终值。问题似乎不是我认为的那一行
问题是在父对象中有两个lambda引用字段:编译器生成一个包含两个方法的类和一个对父类的引用(this
)
我认为这将是一个问题,因为对this
的引用可能会留在TaskCompletionSource对象中,从而阻止它被GCed。至少我在这个问题上的发现表明了这一点
生成的类看起来像这样(显然名称将不同且不可命名):
我认为编译器这样做的原因可能是效率,因为两个lambda都使用TaskCompletionSource
;但是现在,只要对其中一个lambda的引用仍然被引用,对请求
对象的引用也会被保留
不过,我还没有找到解决这个问题的办法
编辑:很明显,我在写这篇文章的时候并没有考虑到这一点。我通过如下更改方法解决了问题:
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;
}
}
公共任务任务响应
{
得到
{
var tcs=new TaskCompletionSource();
Timeout.appeated+=(e,a)=>tcs.SetException(新的TimeoutException(“timeat”+a.SignalTime));
如果(_response!=null)tcs.SetResult(_response);
else ResponseHandler+=tcs.SetResult;//事件传递一个Response(derp)类型的对象,然后将该对象分配给_Response字段。
返回tcs.Task;
}
}
我应该提到,警告出现在第一个lambda(超时事件)上,而不是第二个lambda上。此外,您所描述的是对_响应的捕获,而不是“this”reference@user1447072:将回答中的\u response
替换为Timeout
),但它不应该捕获超时变量?(lambda中没有任何地方引用它)。@AaronMaslen#1:否。Lambdas捕获变量或参数,例如this
<代码>\u response
实际上是这个。\u response
,它捕获了这个
。我记得,我不认为它捕获了这个
——从某种意义上说,编译器生成的类只包含response
类型的单个字段,这是对这个的引用。\u response
。但是,必须检查拆卸以确认。无论如何,这是一个没有实际意义的问题,因为这一行不是引起警告的那一行。将if语句或超时事件行移动到单独的方法会删除警告,但我觉得这不是一个理想的解决方案
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;
}
}