从ForEachAsync中向外部集合添加项目,隐含捕获的闭包

时间:2016-12-30 23:06:24

标签: c# async-await

首先,正如他们所说,我对异步操作充分了解是危险的。 Resharper给我一个警告,下面的代码我在ForEachAsync上有一个隐式捕获的“响应”对象的闭包。我理解为什么它会警告我,但我不确定我的实现是否存在任何特殊错误(顺便说一下,这确实有效),或者是否有更合适的方法来填充ForEachAsync中的“orders”集合。

  public async Task<Response<IEnumerable<Order>>> HandleGetOrdersAsync(GetAllOrdersQuery query)
  {
     Expression<Func<Order, bool>> dateTimeFilter = order =>
        order.OrderTime >= query.StartDateTime &&
        order.OrderTime <= query.EndDateTime;

     Expression<Func<order, bool>> isActiveFilter = order =>
        !query.IsComplete ||
        order.OrderStatus == OrderStatusName.Complete;

     var items = _ctx.orders
        .Include(c => c.Customers)
        .Include(p => p.Payments)
        .Where(dateTimeFilter)
        .Where(isActiveFilter)
        .OrderBy(n => n.OrderNo)
        .Skip(query.PageSize * query.Page)
        .Take(query.PageSize)
        .Select(o => o);

     // ... items count to be performed here ...

     var response = new Response<IEnumerable<Order>>();
     var orders = new List<Order>();

     await items.ForEachAsync(i =>
     {
        var order = new Order
        {
           ResultNo = i.OrderNo,
           CustomerName = i.Customer.Name,
           PaymentType = i.Payment.Type
        };

        orders.Add(order);

     }).ContinueWith(t =>
     {
        response = new Response<IEnumerable<Order>>(orders);
     });

     return response;
  }

1 个答案:

答案 0 :(得分:1)

您的代码将按照您已注意到的方式运行,但代理将保持orders变量处于活动状态,因为它具有对它的引用,因此只要代理人,您的类就无法被GC收集没有资格进行垃圾收集。

 var orders = new List<Order>();

 await items.ForEachAsync(i =>
 {
    var order = new Order
    {
       ResultNo = i.OrderNo,
       CustomerName = i.Customer.Name,
       PaymentType = i.Payment.Type
    };

    orders.Add(order);

 }).ContinueWith(t =>
 {
    response = new Response<IEnumerable<Order>>(orders);
 });

如果orders是值类型,例如int?

,该怎么办?

在这种情况下,它不适用,但如果orders是一个整数且没有await并且代码在捕获orders变量的委托之后继续,那么在委托之后修改变量,并在稍后调用委托(想想事件处理程序)它将使用修改后的副本。为什么?因为事件虽然是整数,但是会捕获引用。

我想Resharper只是警告你,你需要决定它是否会引起你的问题。它所能做的就是警告你,因为在某些情况下它会引起问题,而在其他情况下它不会引起任何问题。