C
C#•3w ago
YetAnohterOne

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
ero
ero•3w ago
@mtreit
mtreit
mtreit•3w ago
Responses may be delayed as I am currently on vacation
No description
YetAnohterOne
YetAnohterOneOP•3w ago
I wish you score par every time! 🙂 🙂 🙂
Sossenbinder
Sossenbinder•3w ago
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
Unknown User•3w ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX•3w ago
If you have no further questions, please use /close to mark the forum thread as answered
Sehra
Sehra•3w ago
that's netfw, newer does not enumerate unless it have to https://source.dot.net/#System.Linq/System/Linq/AnyAll.cs,8788153112b7ffd0
FusedQyou
FusedQyou•3w ago
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 know
asdf
asdf•3w ago
What exactly do you mean by undefined behavior
FusedQyou
FusedQyou•3w ago
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
Anton
Anton•3w ago
You're right, IsEmpty should be a thing
FusedQyou
FusedQyou•3w ago
Isn't it?
Anton
Anton•3w ago
Meanwhile, one can overload Any for concrete types iirc it only exists on spans and memory
FusedQyou
FusedQyou•3w ago
Ohhhh
Anton
Anton•3w ago
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)
FusedQyou
FusedQyou•3w ago
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
Anton
Anton•3w ago
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
FusedQyou
FusedQyou•3w ago
How do you expect it to become a property?
Anton
Anton•3w ago
what do you mean? it would just be on concrete collection types
FusedQyou
FusedQyou•3w ago
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"
Anton
Anton•3w ago
well it is an abstraction
FusedQyou
FusedQyou•3w ago
You basically divide the term into two different things. People check if length is 0, people use this property
Anton
Anton•3w ago
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
FusedQyou
FusedQyou•3w ago
But why Because length == 0 might not mean it's empty? 🤔
Anton
Anton•3w ago
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
FusedQyou
FusedQyou•3w ago
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, though
Anton
Anton•3w ago
I 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
FusedQyou
FusedQyou•3w ago
I still think it's silly though. I think most people just forget it exists
TldrOlli
TldrOlli•3w ago
OOO

Did you find this page helpful?