Search code examples
c#linqarchitectureperformance-testing

C# Best Practices when using !=null, Count > 0, and .Any()


Out of curiosity, what are the underlying differences between !=null, Count > 0, and .Any(), and when is the optimal time to use each? - for both architectural and performance.

I know that .Any() is for IEnumerables, not lists, but I find myself using them (!=null and Count > 0) interchangeably when allowed to. I don't want to get into the habit if it is bad practice.


Solution

  • The way Enumerable.Any works, is the following

    public static bool Any<TSource>(this IEnumerable<TSource> source)
    {
        if (source == null)
            throw Error.ArgumentNull(nameof (source));
        using (IEnumerator<TSource> enumerator = source.GetEnumerator())
        {
            // Returns very early if there are any items
            if (enumerator.MoveNext())
                return true;
        }
        return false;
    }
    

    There is some overhead, but not that much, really, hence I'd assume that Any() performs comparably performant to List<T>.Count (the IEnumerable extension tries to fall back to that value, hence this should be comparable, too).

    Clarity-wise, it eventually boils down to a matter of taste. Personally I like the expressiveness of Any(), for it's a bit closer to natural language to me.

    rows.Any()
    

    makes me think less than

    rows.Count == 0
    

    But not that much.

    null comparison works in a totally different way. If this is not clear to you, you should educate yourself about value and reference types in C# (warning: Things have become a bit different lately, since value types do not allow null by default in current versions of C#/.NET).

    Summarized: Reference types are stored differently and the actual variable is (kind of) just a pointer to where the data is stored (not 100% accurate). Classically pointers in C++ could take the value 0 to indicate that there is no data they point to, which was carried over (at least as a concept) to C# (and other C-like languages as Java). Anyway, since the pointers are not accessed directly in C#, null was invented to indicate that the variable does not point to actual data ("there is no data associated with that variable"). Hence comparing a List<int> variable with null means that you ask whether the list instance has been created at all, which is a nescessary, but not a sufficient criteria for the actual list items being stored.