При вызове Any() на нулевом объекте он генерирует исключение ArgumentNullException в С#. Если объект имеет значение null, определенно не "any", и он должен, вероятно, возвращать false.
Почему С# ведет себя так?
При вызове Any() на нулевом объекте он генерирует исключение ArgumentNullException в С#. Если объект имеет значение null, определенно не "any", и он должен, вероятно, возвращать false.
Почему С# ведет себя так?
При работе со ссылочными типами значение null семантически отличается от "пустого" значения.
null строка - это не то же string.Empty, что и string.Empty, а null IEnumerable<T> не совпадает с Enumerable.Empty<T> (или любым другим "пустым" перечислением этого типа).
Если Any не был методом расширения, вызов его на null привел бы к NullReferenceException. Поскольку это метод расширения, бросание некоторого исключения (хотя и не обязательно) является хорошей идеей, потому что оно сохраняет известную семантику попытки вызвать метод на null: BOOM!
Any() спрашивает: "В этом поле содержатся какие-либо элементы?"
Если поле пусто, ответ явно нет.
Но если в первую очередь нет ящика, тогда вопрос не имеет смысла, и функция жалуется: "О чем, черт возьми, вы говорите? Нет коробки".
С современным С# вы можете легко обработать сценарий OP с помощью простой проверки, например, такой:
List<string> foo = null;
if (foo?.Any() ?? false)
{
DoStuff();
}
Это похоже на неудачную реализацию AnyOrDefault(bool default), которую ОП ожидает от метода расширения Any().
Вы можете легко превратить это в расширение вроде этого:
public static bool HasItems<T>(this IEnumerable<T> source)
{
return (source?.Any() ?? false);
}
Честно говоря, мне не очень нравится имя Переименован в AnyOrDefault для этого, так как не имеет смысла передавать значение по умолчанию (значение по умолчанию true, вероятно, было бы довольно плохо для людей, читающих код позже).HasItems, как предлагается в комментариях. Это гораздо лучшее имя!
Any() представляет собой метод расширения, так что this на самом деле передается в качестве первого аргумента метода. В этой ситуации, понятным для него, чтобы передать ArgumentNullException, this null.
Вы можете выполнить проверку заранее:
bool hasAny = yourData == null ? false : yourData.Any(yourPredicate);
Потому что Any() это метод расширения следующим образом:
public static bool Any(this IEnumerable enumerable)
{
if (enumerable == null)
throw ArgumentNullException("enumerable");
...
}
Any метод работает против IEnumerable и сообщает вам, есть ли какие-либо элементы в Enumerable. Если вы не дадите ему что-либо, чтобы перечислить, то аргумент ArgumentNullException является разумным: коллекция без элементов (совпадающих) не отличается от коллекции.
Как уже упоминалось, Any проверяют, содержит или нет последовательность элементов. Это не мешает вам передавать null значения (что может быть ошибкой в первую очередь).
Каждый метод расширения в классе Enumerable генерирует ArgumentNullException если source имеет значение null. Throwing ArgumentNullExceptions в расширениях - это хорошая практика.
Any() - это метод расширения, который выбрасывает ArgumentNullException, если источник нулевой. Будете ли вы выполнять действие ни на что? В общем, лучше получить какой-то явный индикатор того, что происходит в коде, а не значение по умолчанию.
Но это не значит, что так не может быть. Если вы знаете, что делаете, напишите свою собственную реализацию.
Я просто хотел поделиться с вами некоторыми практическими советами, которым следит моя компания.
Мы пишем наши пользовательские пакеты, предоставляемые частным NuGet, которые широко используются в наших продуктах. Проверка, является ли список пустым/пустым, очень часто, поэтому мы решили написать нашу реализацию Any, которая делает наш код короче и проще.