Рекомендуемый способ проверки, является ли последовательность пустой

Метод возвращает последовательность 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...
 }