Reputation: 8099
I had a strange bug i don't understand, and changing LINQ's IEnumerable to list half way through fixed it, and i dont understand why
Not Real the Code, but very similar The code below doesn't work:
// an IEnumerable of some object (Clasess) internally an array
var ansestors = GetAnsestors();
var current = GetCurrentServerNode();
var result = from serverNode in ansestors
select new PolicyResult
{
//Some irrelevant stuff
OnNotAvailableNode = NodeProcessingActionEnum.ContinueExecution,
};
var thisNode = new PolicyResult
{
//Some irrelevant stuff
OnNotAvailableNode = NodeProcessingActionEnum.ThrowException,
};
result = result.Reverse();
result = result.Concat(new List<PolicyResult> { thisNode });
result.First().OnNotAvailableNode = NodeProcessingActionEnum.ThrowException;
// When looking in the debugger, and in logs, the first element of the
// result sequence has OnNotAvailableNode set to ContinueExecution
// Which doesnt make any sense...
But when i change the ending to the following it works:
result = result.Reverse();
result = result.Concat(new List<PolicyResult> { thisNode });
var policyResults = result.ToList();
var firstPolicyResult = policyResults.First();
firstPolicyResult.OnNotAvailableNode = NodeProcessingActionEnum.ThrowException;
return policyResults;
All the types here are classes (reference types) except NodeProcessingActionEnum which is an enum.
Is this a bug?
Me missing something crucial about LINQ?
Help?
Upvotes: 2
Views: 163
Reputation: 273844
result.First()
executes the (deferred / lazy) query.
That line will set the value OK but when you use result
later the query will be executed again.
Later you are looking at a newly fetched copy. The fact that it is different lets me assume that GetAnsestors()
is also lazily evaluated and is not an in memory List<>
This means that ToList()
is a worthwhile optimization as well as a fix. Note that after the ToList you can also use
var firstPolicyResult = policyResults[0];
Upvotes: 5
Reputation: 34418
The problem is that running Actually I've changed my mind - that's probably not it. This solution might be worth a shot, though.First
on your IEnumerable removes it from the enumerator so you've then checking the next element.
You could wrap the IEnumerable with something which makes the change for you, e.g. using the Select
override which accepts an index too:
var modifiedResults = results.Select((r, index) => {
if (index == 0) {
// This is the first element
r.OnNotAvailableNode = NodeProcessingActionEnum.ThrowException;
}
return r;
});
(untested) should do the trick.
Upvotes: 0