Лучший способ проверить наличие элементов в списке? - PullRequest
8 голосов
/ 09 ноября 2011

Если я хочу выполнить такие действия, как .Where (...) или .Max (...), мне нужно убедиться, что список не равен нулю и имеет число больше нуля.Кроме того, что каждый раз, когда я хочу использовать список, нужно что-то вроде следующего:

if(mylist != null && mylist.Count > 0)
{...}

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

Ответы [ 8 ]

9 голосов
/ 09 ноября 2011
public static class LinqExtensions
{
     public static bool IsNullOrEmpty<T>(this IEnumerable<T> items)
     {
           return items == null || !items.Any();
     }
}

Затем вы можете сделать что-то вроде

if (!myList.IsNullOrEmpty())
 ....
3 голосов
/ 09 ноября 2011

Мое общее предпочтение - иметь пустые экземпляры списка вместо пустых переменных списка. Тем не менее, не каждый может уговорить своих сотрудников в этой договоренности. Вы можете защитить себя от переменных нулевого списка, используя этот метод расширения.

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

Вызывается:

Customers result = myList.EmptyIfNull().Where(c => c.Name == "Bob");

Большинство методов linq работают с пустыми коллекциями. Два метода, которые не являются Мин и Макс. Обычно я вызываю эти методы против IGrouping. Большинство реализаций IGrouping имеют по крайней мере один элемент (например, IGroupings, сгенерированный GroupBy или ToLookup). Для других случаев вы можете использовать Enumerable.DefaultIfEmpty.

int result = myList.EmptyIfNull().Select(c => c.FavoriteNumber).DefaultIfEmpty().Max();
2 голосов
/ 09 ноября 2011

Используйте empty коллекции вместо null коллекций.Where будет отлично работать с пустой коллекцией, поэтому вам не нужно указывать Count > 0 перед ее вызовом.Вы также можете позвонить Max на пустую коллекцию, если вы сначала выполните бит гимнастики .

Для IEnumerable<T> используйте Enumerable.Empty<T>()

Для T[]используйте new T[0]

для List<T> используйте new List<T>()

2 голосов
/ 09 ноября 2011

Не позволяйте списку быть нулевым

Убедитесь, что объект всегда находится в допустимом состоянии.Убедившись, что список никогда не равен нулю, вам никогда не нужно проверять, что список пуст.

public class MyClass
{
    private readonly IEnumerable<int> ints;

    public MyClass(IEnumerable<int> ints)
    {
        this.ints = ints;
    }

    public IEnumerable<int> IntsGreaterThan5()
    {
        return this.ints.Where(x => x > 5);
    }
}

Даже если этот список пуст, вы все равно получите верный IEnumerable<int> обратно.

Максимальные и минимальные перегрузки с типами Nullable

Это все еще не решает проблемы "Max" и "Min", хотя.Существует перегрузка Макс и Мин, которые принимают селекторы.Эти перегрузки селектора могут возвращать обнуляемые целые числа, поэтому ваш метод max становится следующим:

this.ints.Max(x => new int?(x));

Поэтому вы запускаете Max и проверяете, получили ли вы нулевое значение или целое число обратно.вуаля!

Другие параметры

Пользовательские методы расширения

Вы также можете написать свои собственные методы расширения.

public static MinMaxHelper()
{
    public static int? MaxOrDefault(IEnumerable<int> ints)
    {
        if(!ints.Any())
        {
            return null;
        }

        return ints.Max();
    }

    public static int MaxOrDefault(IEnumerable<int> ints, int defaultValue)
    {
        if(!ints.Any())
        {
            return defaultValue;
        }

        return ints.Max();
    }
}

Переопределение методов расширения Linq

И, наконец, помните, что сборка в методах расширения Linq может быть заменена вашими собственными методами расширения с соответствующими сигнатурами.Следовательно, вы можете написать метод расширения для замены .Where (...) и .Max (...), чтобы он возвращал null (или значение по умолчанию), вместо того, чтобы выдавать ArgumentNullException, если Enumerable равен null.

1 голос
/ 09 ноября 2011

Вам не нужно проверять Count, чтобы позвонить Where.Max нужен непустой список для типов значений, но это можно преодолеть с помощью встроенного преобразования, например,

int? max = new List<int>().Max(i => (int?)i); // max = null
1 голос
/ 09 ноября 2011

можно использовать ??Оператор, который преобразует значение NULL в значение, указанное вами справа:

public ProcessList(IEnumerable<int> ints)
{
    this.ints = ints ?? new List<int>();
}

Кстати: обработка пустого списка с помощью LINQ не является проблемой.

1 голос
/ 09 ноября 2011

Если существует риск того, что ваш список будет нулевым, вам всегда нужно будет проверить это перед вызовом любого из его методов, но вы можете использовать метод Any () вместо count. Это вернет true, как только будет считаться один элемент, независимо от того, есть ли один или несколько элементов в списке. Это экономит итерации по всему списку, что и делает Count:

if(mylist != null && mylist.Any())
{...}
1 голос
/ 09 ноября 2011

Вы можете попробовать myList.Any() вместо .Count, но вам все равно нужно проверить на null.

...