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.
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
{
}