Parallel.ForEach显然是克隆引用类型?

时间:2014-02-05 16:26:30

标签: .net parallel.foreach

我有一个简单的方法:

private IEnumerable<OrderResult> SubmitOrders(IEnumerable<OrderItem> items)
    {
        ConcurrentBag<OrderResult> results = new ConcurrentBag<OrderResult>();

        Parallel.ForEach(items, item =>
            {
                OrderResult result = SubmitOrder(item);
                results.Add(result);
            });

        return results;
    }

要添加更多上下文,上面引用的SubmitOrder(item)方法会将'item'对象的“Sent”(DateTime?)属性更改为DateTime.Now,如果订单已成功提交。

在Parallel.ForEach循环中,在SubmitOrder(item)之后,我可以看到“已发送”属性已正确更新。

但是,如果我检查传入的“items”参数中的对象,则没有任何“已发送”属性已更新。就好像传递给Parallel.ForEach循环的项目不是原始“items”集合中的项目。

这是为什么?如果在循环中修改了传入集合中的对象,我希望更改能够反映在原始集合中的项目中,但它们似乎不是。

1 个答案:

答案 0 :(得分:4)

items的参数类型为IEnumerable<OrderItem>。如果尚未枚举items,并且枚举它们会创建新对象,那么这可能是原因,因为您在SubmitOrder()中更新的对象与下次的对象不同枚举items。这是一个完整的LINQPad C#程序,它演示了我的意思。

void Main()
{
    IEnumerable<OrderItem> itemsAsIEnumerable =
        Enumerable
            .Range(1, 5)
            .Select(i => new OrderItem() { ItemNumber = i });
    SubmitOrders(itemsAsIEnumerable);
    itemsAsIEnumerable.Dump();
        /* Displays:
        ItemNumber Sent
        1 null 
        2 null 
        3 null 
        4 null 
        5 null 
        */

    IEnumerable<OrderItem> itemsAsList =
        Enumerable
            .Range(1, 5)
            .Select(i => new OrderItem() { ItemNumber = i })
            .ToList();
    SubmitOrders(itemsAsList);
    itemsAsList.Dump();
        /* Displays:
        ItemNumber Sent
        1 2/5/2014 10:01:58 AM
        2 2/5/2014 10:01:58 AM
        3 2/5/2014 10:01:58 AM
        4 2/5/2014 10:01:58 AM
        5 2/5/2014 10:01:58 AM
        */      
}

private IEnumerable<OrderResult> SubmitOrders(IEnumerable<OrderItem> items)
{
    ConcurrentBag<OrderResult> results = new ConcurrentBag<OrderResult>();

    Parallel.ForEach(items, item =>
        {
            OrderResult result = SubmitOrder(item);
            results.Add(result);
        });

    return results;
}

private OrderResult SubmitOrder(OrderItem item)
{
    item.Sent = DateTime.Now;
    return new OrderResult();
}

public class OrderItem
{
    public int ItemNumber { get; set; }

    public DateTime? Sent { get; set; }
}

public class OrderResult
{
}