I have a collection of objects entering a method as an IEnumerable
of which I am grouping them by a reference property and then processing them group by group. The processing involves mutating the other properties of the objects. When the method completes and returns, the caller expects to have the collection of objects it passed in to be mutated. The whole process is asynchronous and the method looks like the following:
public async Task MutateMyObjects(IEnumerable<MyObjects> myObjects,
CancellationToken cancellationToken)
{
var myObjectsGroupedByGroupingEntity = myObjects
.GroupBy(myObject => myObject.GroupingEntity);
foreach (var myObjectGroup in myObjectsGroupedByGroupingEntity )
{
await ProcessGroup(myObjectGroup.Key, myObjectGroup, cancellationToken);
}
}
Both MyObject
and GroupingEntity
are classes, as such my expectation is that MyObject
s are passed as reference types and mutation is inherent through the process.
What actually happens is the caller of MutateMyObjects
observes the same property values of MyObject
s as it observed before the method call. These results are observed after the Task
completes. While debugging the method above, observing the variable states before the method returns shows that the object collection under the variable myObjectGroup
contain the mutated properties while the object collection under the variable myObjects
does not.
I'm not sure what aspect of my understanding is missing causing me to get the wrong expectation, any insights would be greatly appreciated.
CodePudding user response:
The issue is that I needed to execute the LINQ query first to materialise the objects before sending them off for mutation. What isn't shown in the question is how the IEnumerable<MyObject> myObjects
is represented. In my case, myObjects
was a deferred execution of a database fetch piped into an object mapping. This meant that when I mutated the objects, the groupBy
forced the initialisation of the objects which were subsequently lost when the shown method returned. When the "mutated" objects were "used", the objects were in fact reinitialised.
As pointed out by @Enigmativity, in this method, the signature should probably be asking for IList<MyObject>
to be sure of the existence of the objects as the method intends to mutate them. This means that the caller of the method is required to execute any LINQ queries before calling the method thereby avoiding this pitfall.