CA1860: Avoid using 'Enumerable.Any()' extension method
https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1860
Does this rule make any sense?
The rule description says: "To determine whether a collection type has any elements, it's more efficient and clearer to use the Length, Count, or IsEmpty (if possible) properties than to call the Enumerable.Any method. Any(), which is an extension method, uses language integrated query (LINQ). It's more efficient to rely on the collection's own properties, and it also clarifies intent."
Does using Count truly clarify intent? I was always using .Any() because I thought it is far clearer -
Count != 0
just asks to be extracted into a method, the intent is not to check the number of elements, but whether the collection has Any elements.
I really miss an Empty
property or method, but the next best thing is !collection.Any()
or, even better, an extension method: public static Empty<T>(this IEnumerable<T> enumerable) => !enumerable.Any()
.
But VisualStudio yells at me now and suggests me to use Count == 0
or Count != 0
instead.
Also note that Count
bears the risk of accidentally messing up !=
with ==
or vice-versa.
The rule description mentions the IsEmpty
property, but note that the two most common cases (List and Array) have no such property.
Finally the rule mentions performance, but isn't this a typical case of premature optimization? Unless I'm in a tight loop, the 10ms saved by avoid .Any()
won't matter, and .Any()
does seem clearer, which is what matters.
Am I missing something? Are there really any outstanding reasons to avoid Any()
? Because I feel ready to rebel and just suppress this suggestion.CA1860: Avoid using 'Enumerable.Any()' extension method - .NET
Learn about code analyzer rule CA1860 - Avoid using 'Enumerable.Any()' extension method
30 Replies
@mtreit
Responses may be delayed as I am currently on vacation

I wish you score par every time! 🙂 🙂 🙂
I feel like in the case of this rule you are free to ignore it if you are not concerned with the microoptimization and don't like the style
It's also a matter of taste
I personally prefer the concrete properties anyways because it's a quick and obvious telltale sign that the collection is in fact a materialized collection and not an IEnumerable<T>
You could also look into pattern matching instead, e.g.
x is { Count: > 0}
Unknown User•3w ago
Message Not Public
Sign In & Join Server To View
If you have no further questions, please use /close to mark the forum thread as answered
Yes, makes sense
Any
starts an enumeration.
https://github.com/microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs#L1288that's netfw, newer does not enumerate unless it have to https://source.dot.net/#System.Linq/System/Linq/AnyAll.cs,8788153112b7ffd0
Instead you want to get the count directly because:
- Its more efficient to use the available information of the length instead of determining if elements exist by getting the first item through iteration.
-
Any
will enumerate the enumberable which means possible invoking code or iterating a collection multiple times leading to undefined behaviour.
The latter is more important since the performance difference is pretty negligible.
It's also cleaner because generally shou should not rely on an enumerable when you know the collection. LINQ generally intends to find a collection type from an IEnumerable which is, once again, a bit of a performance hit. If you know the collection, you should use the collection directly.
Oh, yeah, I was confused because I expected type matching. I should learn to use https://source.dot.net/.
But yeah, you see how it still attempts to do pattern matching and possible enumeration to get the correct type which might or might not result in undefined behavior.
I'm not good with the compiler and its optimizations, but generally this would result in worse code as far as I knowWhat exactly do you mean by undefined behavior
An IEnumerable is meant to be iterated. With general controls this is just a case of going to the next index and returning this. However, you can also make a method that returns an IEnumerable. When you iterate that, a lot of code can be invoked before an item is returned. Imagine if it's based on a state, or you might be modifying data before you return an item. You now risk iterating this logic twice and either working with two different states, or modifying a state twice. This is why you should generally make sure to iterate an enumerator immediately after you retrieve it, and put it in an array or list or another type.
It's a bit hard to explain, an example might be better
You're right,
IsEmpty
should be a thingIsn't it?
Meanwhile, one can overload
Any
for concrete types
iirc it only exists on spans and memoryOhhhh
it should be added to dictinnaries, lists and such
the OP is right about the count check thing
Using a length check is not really premature optimization. I think it's more of a case of non-pessimization (in Casey Muratori's terms) — using Linq is not easier or better or more maintainable, it's just always slower. But I agree that
IsEmpty
should be an abstraction (aka an actual property)IsEmpty
feels weird
It just exists as an alias to "length is 0"in that case. It's different compared to Any
because Any
actually checks for items using different methods. Even if IsEmpty
checks for length it would just be an inverse Any
A certain collection may not keep track of the count
while still knowing that it has items
IsEmpty is a totally reasonable abstraction
considering this
How do you expect it to become a property?
what do you mean?
it would just be on concrete collection types
You know the whole issue is that an IEnumerable does not define the underlying collection, just how it's iterated. It can't be added there, so at that point you have to either find the underlying collection, or attempt to iterate. This is what
Any
does
Even if it was added to a collection it seems entirely pointless since it's just an alias to "length is 0"well it is an abstraction
You basically divide the term into two different things. People check if length is 0, people use this property
an abstraction doesn't necessarily mean being on an interface
it just means that the concept of being empty is now acknowledged as a separate thing
But why
Because
length == 0
might not mean it's empty? 🤔no, because sometimes it's count, sometimes it's length, and sometimes there's neither
or maybe there's a specialized way to check for being empty
while getting the length is costly
Pretty sure every collection type with an explicit length implements
IList
/ICollection
, so they'd all have a Count
Otherwise I suppose maybe you can add an extension method on the interface that adds it (the IsEmpty
)
Won't be a property then, thoughI mean, properties can still exist on concrete collection types
Why does IsEmpty exist for spans when you could just check the length?
Presumably because it was a useful abstraction
yeah this should exist imo
just in the standard library
I still think it's silly though. I think most people just forget it exists
OOO