Question

I have a simple method:

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;
    }

To add further context, the SubmitOrder(item) method referenced above changes the "Sent" (DateTime?) property on the 'item' object to DateTime.Now, if the order is submitted successfully.

Inside the Parallel.ForEach loop, after SubmitOrder(item), I can see that the "Sent" property has been updated correctly.

HOWEVER, if I examine the object in the passed in "items" parameter, then none of the "Sent" properties have been updated. It is as though the items being passed into the Parallel.ForEach loop aren't those in the original "items" collection.

Why is this? If the objects in the passed in collection were modified in the loop, I expected the changes to be reflected in the items in the original collection, but they don't appear to be.

Était-ce utile?

La solution

The parameter type of items is IEnumerable<OrderItem>. If items hasn't been enumerated yet, and enumerating them creates new objects, then that could be the cause, as the objects you're updating in SubmitOrder() are not the same as the objects the next time items is enumerated. Here is a full LINQPad C# program that demonstrates what I mean.

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
{
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top