Рекомендуемый способ проверки, является ли последовательность пустой
Метод возвращает последовательность IEnumerable<T>
, и теперь вы хотите проверить, пуст ли он. Как вы это рекомендуете? Я ищу и хорошую читаемость, и хорошую производительность.
Первый и наиболее очевидный способ - проверить, что счетчик больше нуля:
if(sequence.Count() == 0)
Имеет приличную удобочитаемость, но ужасную производительность, поскольку она должна действительно пройти через всю последовательность.
Метод, который я иногда использую, следующий:
if(!sequence.Any())
Это не так (насколько мне известно) нужно пройти через всю последовательность, но читаемость немного отсталая и неудобная. (Читает намного лучше, если мы проверяем, что последовательность не пуста, хотя).
Другой вариант - использовать First
в try-catch, например:
try
{
sequence.First();
}
catch(InvalidOperationException)
{
// Do something
}
Не очень красивое решение, и, вероятно, медленнее, поскольку оно использует исключения и прочее. Могло бы предотвратить это, используя FirstOrDefault
, конечно, за исключением того, что у вас возникла бы большая проблема, если первый элемент в последовательности фактически был значением по умолчанию;)
Итак, любые другие способы проверить, является ли последовательность пустой? Какой из них вы обычно используете? Какой из них вы рекомендуете использовать?
Примечание.. Для оптимальной читаемости я бы, вероятно, поместил один из вышеприведенных фрагментов в метод расширения IsEmpty
, но мне все же интересно, так как я должен был что-то сделать внутри этого метода: р
Ответы
Ответ 1
Я бы использовал !sequence.Any()
лично.
Если вам действительно нужно, вы всегда можете написать свой собственный метод расширения:
public static bool IsEmpty<T>(this IEnumerable<T> source)
{
return !source.Any();
}
Затем вы можете написать:
if (sequence.IsEmpty())
Ответ 2
Вы можете создать метод расширения с этой реализацией.
public static bool IsEmpty<T>(this IEnumerable<T> items) {
using (var enumerator = items.GetEnumerator())
{
return !enumerator.MoveNext();
}
}
Ответ 3
Ну, все эти методы, которые вы вызываете, - это методы расширения LINQ, поэтому это зависит от того, как был реализован поставщик LINQ. Если вы хотите знать, является ли последовательность пустой, то подходит Count() == 0
или Any() == false
. Я предпочитаю Any()
себя.
Однако, в зависимости от того, какой фактический тип имеет ваш sequence
, вам может не понадобиться использовать метод расширения LINQ. То есть если это массив, вы можете вызвать sequence.Length
. Если это коллекция, вы можете использовать sequence.Count
.
Ответ 4
Ты сказал:
if(sequence.Count() == 0)
Имеет приличную удобочитаемость, но ужасную производительность, поскольку она должна действительно пройти через всю последовательность.
Это правда? Вы говорите о работе с интерфейсом IEnumerable<T>
, и все же вы делаете предположения относительно его реализации, которые могут быть или не быть правдой. Фактически, многие пользовательские коллекции, которые я написал за эти годы, содержат закрытую переменную, которая хранит текущий счет внутри, а это означает, что возвращение .Count
является тривиальным вопросом, который не требует итерации всей коллекции.
Таким образом, если вы не знаете, что конкретная реализация плохо оптимизирована для .Count
, я бы использовал .Count
. Избегайте преждевременной оптимизации, где это возможно, и придерживайтесь удобочитаемости.
Ответ 5
Я использую эти методы расширения, чтобы определить, является ли последовательность нулевым или не имеет какого-либо элемента, и, альтернативно, определить, имеет ли последовательность, по крайней мере, один элемент, как метод string.IsNullOrEmpty()
.
public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
if (source == null) {
return true;
}
return !source.Any();
}
public static bool IsNotNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
return !source.IsNullOrEmpty();
}
.
.
.
if (!sequence.IsNullOrEmpty()) {
//Do Something with the sequence...
}