关闭分配的含义和问题

时间:2018-04-16 17:10:48

标签: c# resharper rider

我正在使用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'参考

我在谷歌搜索时发现了一些东西,但我仍然不知道这意味着什么,问题是什么?

2 个答案:

答案 0 :(得分:4)

此消息来自Heap Allocations Viewer插件。当您创建lambda以Func传递给GetOrCreateAsync时,您将从调用方法(GetTicket)中捕获一些值,并在以后使用它们。< / p>

编译此代码时,编译器会将此lambda重写为一个包含值的类,以及一个与lambda主体相同的方法,尽管它将使用此新类中捕获的值,并且不是原来的方法调用。

Heap Allocations Viewer插件所说的是在运行时发生了一个隐藏的分配 - 正在分配这个新的编译器生成的类,分配的值和调用的方法。

插件告诉你id正在这个新类中被捕获和分配 - 这在lambda中很明显,因为你在代码中看到了它。但是您还要捕获this,因为GetTicket_uncached是实例方法而不是静态方法。您无法在没有this的情况下调用实例方法,因此在编译器生成的类中捕获并分配idthis

您无法摆脱id变量的分配,但如果您使this为静态,则可以删除GetTicket_uncached引用(但这可能需要传入ServiceAddress,在这种情况下,堆分配查看器会告诉您现在关闭分配是idServiceAddress)。

您可以在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中,您应对所有其他对象执行相同操作,可以在闭包范围之外修改,创建本地版本