Рекомендуемый способ проверить, является ли последовательность пустой - PullRequest
47 голосов
/ 19 января 2010

Метод возвращает последовательность, IEnumerable<T>, и теперь вы хотите проверить, является ли она пустой. Как вы рекомендуете это делать? Я ищу как хорошую читабельность, так и хорошую производительность.

Первый и самый очевидный способ - проверить, что число больше нуля:

if(sequence.Count() == 0)

Имеет приличную читаемость, но ужасную производительность, так как фактически должен пройти всю последовательность.

Метод, который я иногда использую, следующий:

if(!sequence.Any())

Это (насколько я знаю) не должно проходить всю последовательность, но читаемость немного неловкая и неловкая. (Читается намного лучше, если мы проверяем, что последовательность не пуста, хотя).

Другой вариант - использовать First в режиме try-catch, например:

try
{
    sequence.First();
}
catch(InvalidOperationException)
{
    // Do something
}

Не очень красивое решение и, возможно, более медленное, поскольку оно использует исключения и прочее. Можно предотвратить это, используя, конечно, FirstOrDefault, за исключением того, что у вас будет большая проблема, если первый элемент в последовательности будет значением по умолчанию;)

Итак, есть ли другие способы проверить, является ли последовательность пустой? Какой из них вы обычно используете? Какой из них вы рекомендуете использовать?

Примечание: Для оптимальной читабельности я бы, вероятно, поместил один из приведенных выше фрагментов в метод расширения IsEmpty, но мне все равно любопытно, поскольку мне пришлось бы что-то делать внутри этого метода, как скважина: p

Ответы [ 6 ]

81 голосов
/ 19 января 2010

Я бы использовал !sequence.Any(), лично.

Если вам действительно нужно, вы всегда можете написать свой собственный метод расширения:

public static bool IsEmpty<T>(this IEnumerable<T> source)
{
    return !source.Any();
}

Тогда вы можете написать:

if (sequence.IsEmpty())
6 голосов
/ 19 января 2010

Вы можете создать метод Extension с помощью этой реализации.

public static bool IsEmpty<T>(this IEnumerable<T> items) {
        using (var enumerator = items.GetEnumerator())
        {
            return !enumerator.MoveNext();
        }
 }
2 голосов
/ 19 января 2010

Ну, все эти методы, которые вы вызываете, являются методами расширения LINQ, поэтому это зависит от того, как был реализован поставщик LINQ. Если вы хотите узнать, является ли последовательность пустой, подойдет Count() == 0 или Any() == false. Я предпочитаю Any() себя.

Однако, в зависимости от того, какой фактический тип у вас есть sequence, вам может не потребоваться использовать метод расширения LINQ. То есть если это массив, вы можете вызвать sequence.Length. Если это коллекция, вы можете использовать sequence.Count.

0 голосов
/ 11 апреля 2018

Метод, который я иногда использую, следующий:

if(!sequence.Any())

Это (насколько я знаю) не должно проходить всю последовательность, , но читаемость немного неловкая и неловкая.(Читается намного лучше, если мы проверяем, что последовательность не пуста).

  1. Согласно Microsoft, Любой действительно не должны пройти всю последовательность.Цитирование из раздела Примечания :

Перечисление source прекращается, как только может быть определен результат.

Это особенно верно при проверке наличия элементов в операторе if-else.Можно утверждать, что удобочитаемость лучше всего, если проверять наличие элементов в операторе if и отсутствие элементов в else, что позволяет избежать использования оператора !:

if (sequence.Any())
{
}
else
{
}

Большинство считает, что это более читабельно, чем:

if (!sequence.Any())
{
}
else
{
}
0 голосов
/ 14 ноября 2015

Я использую эти методы расширения, чтобы определить, является ли последовательность нулевой или не имеет какого-либо элемента, и альтернативно, чтобы определить, есть ли в последовательности хотя бы один элемент, очень похожий на метод 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...
 }
0 голосов
/ 19 января 2010

Вы сказали:

if(sequence.Count() == 0) Имеет приличную читаемость, но ужасную производительность, так как фактически должен пройти всю последовательность.

Это правда? Вы говорите о работе с интерфейсом , IEnumerable<T>, и все же вы делаете предположения относительно его реализации, которые могут быть или не быть правдой. Фактически, многие из пользовательских коллекций, которые я написал за эти годы, хранят закрытую переменную, которая хранит текущий счетчик внутри, что означает, что возвращение .Count является тривиальным вопросом, который не требует повторения всей коллекции.

Итак, с учетом сказанного, если вы не знаете, что конкретная реализация плохо оптимизирована для .Count, я бы использовал .Count. По возможности избегайте преждевременной оптимизации и придерживайтесь удобочитаемости.

...