Pull to refresh

Проверки на пустые перечисления

Reading time 2 min
Views 11K
Original author: Phil Haack
Недавно, во время разбора кода одной программы я заметил метод, который выглядел примерно так:

public void Foo<T>(IEnumerable<T> items)
{
 if(items == null || items.Count() == 0)
 {
  // Оповестить о пустом перечислении
 }
}



Метод принимает дженерик-перечисление и проверяет, пустое ли оно. Видите ли вы тут потенциальную проблему? Я намекну, проблема в этой строчке:

items.Count() == 0


И в чем же тут проблема? Проблема в том, что эта строчка может оказаться очень неэффективной.

Если вызвать наш метод, передав ему перечисление, которое не реализует ICollection<T> (например, IQueryable результат запроса к Entity Framework или LINQ to SQL), метод Count() будет перебирать всю коллекцию ради выполнения этой проверки.

В случае, когда перечисление реализует ICollection<T>, все в порядке. Метод Count() оптимизирован для таких случаев и проверит свойство Count.

Если говорить человеческим языком, то наша строчка отвечает на вопрос «Количество в перечислении равно нулю?». Но это вовсе не то, что нас интересует. На самом деле нам нужно ответить на вопрос «Есть ли в перечислении хотя бы один элемент?».

Если подойти к задаче таким образом, то решение станет очевидным: использовать расширение Any из пространства имен System.Linq.

public void Foo<T>(IEnumerable<T> items)
{
 if(items == null || !items.Any())
 {
  // Оповестить о пустом перечислении
 }
}



Красота такого метода в том, что ему достаточно вызвать MoveNext интерфейса IEnumerable только один раз! У вас может быть бесконечно большое перечисление, но Any вернет результат немедленно.

Еще лучше было бы, поскольку такая проверка используется постоянно, подумать над реализацией своего простого метода-расширения:

public static bool IsNullOrEmpty<T>(this IEnumerable<T> items)
{
  return items == null || !items.Any();
}



Теперь, с таким методом, исходный код выглядит еще проще:

public void Foo<T>(IEnumerable<T> items)
{
 if(items.IsNullOrEmpty())
 {
  // Оповестить о пустом перечислении
 }
}



С таким методом-расширением в своем инструментарии, вы никогда снова не проверите пустоту перечисления неэффективно.
Tags:
Hubs:
+54
Comments 65
Comments Comments 65

Articles