Regarding Possible multiple enumeration of IEnumerable

This feature behaves in a strange way, mostly that it keeps producing warnings when that is completely the intent of the code.

Some of the code I was working on today that triggered this message

return enumerable.FirstOrDefault(conditional) ?? enumerable.First();

var adminIntersect = model.MemberOf.Intersect(RolesAdmin);
if (adminIntersect.Any())
{
    throw new SecurityException(string.Format("User {0}|{1} attempted to add admin only role(s) {2} to target {3}", _user.UserName, _user.ExternalId, adminIntersect.Concatenate(seperator: ", "), model.Id));
}

I'm not really sure what to suggest here. Perhaps this feature should ignore checks on null coalescing operators, and not count usage of Any() since it's more of a boundary checker and would very likely be used a second as in my 2nd example.

(Note all red highlighted text is where rehsaper gave the squiggly error lines)

3 comments

ReSharper is totally right here.

return enumerable.FirstOrDefault(conditional) ?? enumerable.First();


You're effectively enumerating twice the enumerable, stopping to the first item each time but it's still two different enumerations. If it's a memory list it doesn't matter, if it's a LINQ To SQL or Entities query, it will trigger two databases queries which is probably not what you want. Plus, your code here has no real meaning : if FirstOrDefault() returns null, First() will just throw an exception. Using only First() will do the same.

Any + Concatenate is the same. You're effectively starting twice the enumeration, which in your sample is an Enumerable.Intersect call. Thus, you'll be starting to compute the intersection twice, one stopping at the first item, the other one completely.

IMHO, these warnings are very useful and should be treated seriously. LINQ is great but it's very easy to enumerate way too much time the same thing.

0

Plus, your code here has no real meaning : if FirstOrDefault() returns null, First() will just throw an exception. Using only First() will do the same.


No, because FirstOrDefault has a predicate. The line gets the first item that matches the predicate or if nothing matches it gets the first item in the list.

0

blakel wrote:

Plus, your code here has no real meaning : if FirstOrDefault() returns null, First() will just throw an exception. Using only First() will do the same.


No, because FirstOrDefault has a predicate. The line gets the first item that matches the predicate or if nothing matches it gets the first item in the list.


Precisely, the Any() statement is the exact opposite I'm validating the enumerable has atleast 1 item first, and if so iterate. Both of these are O(N) + O(1) which as we all know is the same as O(N) still.

Complaing about behavior that is still O(N) just wil lead to people disabling this message. Of course maybe I'm wrong and the majority of people don't use linq right and they'll only see these messages for legitimate cases unlike myself.

0

Please sign in to leave a comment.