Why doesn't Any() work on a c# null object

C#.NetObjectIenumerable

C# Problem Overview


When calling [Any()][1] on a null object, it throws an ArgumentNullException in C#. If the object is null, there definitely aren't 'any', and it should probably return false.

Why does C# behave this way?

[1]: http://msdn.microsoft.com/en-us/library/bb337697 "Microsoft Documentation"

C# Solutions


Solution 1 - C#

Any() is asking: "Does this box contain any items?"

If the box is empty, the answer is clearly no.

But if there is no box in the first place, then the question makes no sense, and the function complains: "What the hell are you talking about? There is no box."


When I want to treat a missing collection like an empty one, I use the following extension method:

public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T> sequence)
{
    return sequence ?? Enumerable.Empty<T>();
}

This can be combined with all LINQ methods and foreach, not just .Any().

Solution 2 - C#

With modern C#, you can easily handle the OP's scenario with a simple check like this:

List<string> foo = null;

if (foo?.Any() ?? false)
{
    DoStuff();
}

This is kinda like a lame AnyOrDefault(bool default) implementation that the OP is expecting the Any() extension method to do.

You could easily make this into an extension like this:

public static bool HasItems<T>(this IEnumerable<T> source)
{
    return (source?.Any() ?? false);
}

Honestly, I don't really like the name AnyOrDefault for this since it won't ever make sense to pass in a default value (a default of true would probably be pretty mean to people reading code later). Renamed to HasItems, as suggested in the comments. This is a far better name!

Solution 3 - C#

When dealing with reference types, a null value is semantically different from an "empty" value.

A null string is not the same as string.Empty, and a null IEnumerable<T> is not the same as Enumerable.Empty<T> (or any other "empty" enumerable of that type).

If Any were not an extension method, calling it on null would result in NullReferenceException. Since it is an extension method, throwing some exception (although not necessary) is a good idea because it preserves the well-known semantics of trying to call a method on null: BOOM!

Solution 4 - C#

Any() is an extension method, so this is actually passed as the first argument to the method. In this situation, it's understandable for it to throw ArgumentNullException is this is null.

You can perform the check yourself beforehand:

bool hasAny = yourData == null ? false : yourData.Any(yourPredicate);

Solution 5 - C#

Because Any() it is a extension method like this:

public static bool Any(this IEnumerable enumerable)
{
    if (enumerable == null)
        throw ArgumentNullException("enumerable");
    ...
}

Solution 6 - C#

The Any method runs against an IEnumerable and tells you whether there are any items in the Enumerable. If you don't give it anything to enumerate then an ArgumentNullException is reasonable: a collection with no (matching) elements is different to no collecion.

Solution 7 - C#

As others have already mentioned, Any checks whether or not a sequence contains elements. It does not prevent you from passing null values(what might the bug in the first place).

Every extension method in Enumerable class throws an an ArgumentNullException if the source is null. Throwing ArgumentNullExceptions in extensions actually is good practise.

Solution 8 - C#

Any() is an extension method that throws ArgumentNullException if the source is null. Would you perform an action on nothing? In general, it's better to get some explicit indicator of what's happening in the code rather than the default value.

But it doesn't mean it can't be like that. If you know what you doing, write your own custom implementation.

I just wanted to share with you some practical advice my company is following. We write our custom packages shared with private NuGet that are widely used in our products. Checking if the list is null/empty is very frequent, so we decided to write our implementation of Any which makes our code shorter and simpler.

Solution 9 - C#

Ultimately, the distinction is due to the behavioral differences between no elements and null.

Any() internally attempts to access the underlying sequence (IEnumerable). Since the object can be null, there is no way to access the enumerable to validate it, hence a NullReferenceException is thrown to indicate this behavior.

At first, it sounds like it should just return false since null in a way could mean none.

However, there is different levels of information and behavior occurring here.

  • Any() with 0 elements is a collection with 0 elements.
  • null means no collection.

Any() with 0 elements is a collection. The latter isn't a collection.


Practical real world example

If you have a wallet (underlying sequence), with no cash (elements) inside, you have a wallet, but your broke (no elements). Null means you don't even have a wallet to put cash inside.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDefenestrationDayView Question on Stackoverflow
Solution 1 - C#CodesInChaosView Answer on Stackoverflow
Solution 2 - C#JaxidianView Answer on Stackoverflow
Solution 3 - C#JonView Answer on Stackoverflow
Solution 4 - C#Frédéric HamidiView Answer on Stackoverflow
Solution 5 - C#roxioamView Answer on Stackoverflow
Solution 6 - C#Dan PuzeyView Answer on Stackoverflow
Solution 7 - C#Tim SchmelterView Answer on Stackoverflow
Solution 8 - C#proximabView Answer on Stackoverflow
Solution 9 - C#ReapView Answer on Stackoverflow