我正在使用JetBrains Rider编程C#,我猜这个警告在使用ReSharper时也会出现:
我写了这个函数,GetTicket
:
public async Task<IEnumerable<Ticket>> GetTicket(int id)
{
return await _memoryCache.GetOrCreateAsync(_cachingFunctionalty.BuildCachingName(id), entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(10);
return GetTicket_uncached(id);
});
}
和GetTicket_uncached
,它称之为:
private async Task<IEnumerable<Ticket>> GetTicket_uncached(int id)
{
RestClient client = new RestClient(ServiceAdress);
Request req = new Request
{
Method = Method.GET,
Resource = "api/tickets/get",
Parameters = new {ident = id}
};
return await client.ExecuteRequestAsync<Ticket[]>(req);
}
因此,方法id
中的参数public async Task<IEnumerable<Ticket>> GetTicket(int id)
会突出显示以下警告:
闭包分配:'id'参数和'this'参考
我在谷歌搜索时发现了一些东西,但我仍然不知道这意味着什么,问题是什么?
答案 0 :(得分:4)
此消息来自Heap Allocations Viewer插件。当您创建lambda以Func
传递给GetOrCreateAsync
时,您将从调用方法(GetTicket
)中捕获一些值,并在以后使用它们。< / p>
编译此代码时,编译器会将此lambda重写为一个包含值的类,以及一个与lambda主体相同的方法,尽管它将使用此新类中捕获的值,并且不是原来的方法调用。
Heap Allocations Viewer插件所说的是在运行时发生了一个隐藏的分配 - 正在分配这个新的编译器生成的类,分配的值和调用的方法。
插件告诉你id
正在这个新类中被捕获和分配 - 这在lambda中很明显,因为你在代码中看到了它。但是您还要捕获this
,因为GetTicket_uncached
是实例方法而不是静态方法。您无法在没有this
的情况下调用实例方法,因此在编译器生成的类中捕获并分配id
和this
。
您无法摆脱id
变量的分配,但如果您使this
为静态,则可以删除GetTicket_uncached
引用(但这可能需要传入ServiceAddress
,在这种情况下,堆分配查看器会告诉您现在关闭分配是id
和ServiceAddress
)。
您可以在ReSharper help page for the "Implicitly capture closure" warning中看到更多细节。虽然它讨论了不同的场景和警告消息,但是有关分配类来捕获变量的背景细节很有用。
答案 1 :(得分:2)
期待您的设计如下:
public async Task<IEnumerable<Ticket>> GetTicket(int id)
{
return await _memoryCache.GetOrCreateAsync(_cachingFunctionalty.BuildCachingName(id), entry =>
{
var localId = id;
entry.SlidingExpiration = TimeSpan.FromSeconds(10);
return GetTicket_uncached(localId);
});
}
现在你没有一个可以在闭包范围之外修改的变量,Re-sharper会给出这个警告,理论上可以修改执行闭包之外的变量,从而导致不可预测的结果。同样适用于其他方法。 在act中,您应对所有其他对象执行相同操作,可以在闭包范围之外修改,创建本地版本