2015-02-02 6 views
1

У меня есть пользовательская коллекция IList<user> в качестве пользователей. Когда я попытался проверить users является нулевым или пустым, я не получал разведывательную помощь (как IsNullOrEmpty), поэтому я написал метод ниже удлинительныеIEnumerable vs Ilist - метод расширения IsNullOrEmpty

public static bool IsNullOrEmpty<T>(this IEnumerable<T> source) 
    { 
     if (source.IsNullOrEmpty()) 
     { 
      return true; 
     } 
     return false; 
    } 

К моему удивлению, я обнаружил, что IEnumberable имеет IsNullOrEmpty().

Как мне известно IList расширяет ICollection, который снова продлить IEnumerable, если это так, то IList должен поддерживать IsNullOrEmpty.

Пожалуйста, исправьте, где я ошибаюсь.

+6

'' IEnumerable еще не 'IsNullOrEmpty' метод, это расширение, которое вы написали выше;) Если вы это называете вы получите' StackOverflowException'. –

+0

@TimSchmelter: D Спасибо –

+2

В качестве примечания стороны: 'IEnumerable ' should * not * предполагается повторяемым; единственный способ проверить, является ли последовательность пустой, - начать ее итерацию: если вы начнете ее повторять, она может быть мертвой, сделанной, ушедшей, законченной, никогда не увидившейся снова. –

ответ

4

IEnumerable<T> не имеет способа IsNullOrEmpty, это расширение, которое вы написали выше. Если вы позвоните, вы получите StackOverflowException.

Вы могли бы реализовать это следующим образом:

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

Но важно отметить, что этот метод не является настолько полезным и может даже улучшить в худшую сторону. Потому что Enumerable.Any будет «потреблять» запрос. Поэтому, если это не коллекция в памяти, она должна вызвать GetEnumerator и начать перечисление, чтобы проверить, есть ли хотя бы один элемент. Иногда объект должен быть сопоставлен в случае, если он был перечислит (например, в File.ReadLines в .NET < = 4), который вызовет ObjectDisposedException, если вы попытаетесь снова использовать его позже.

Другой пример, когда этот метод имеет нежелательные побочные эффекты, заключается в том, что последовательность представляет собой запрос, который фильтрует (...Where(x => Compute(x, random.Next()))). Этот запрос может давать разные результаты каждый раз. Процитировать комментарий Марка Гравелла: «IEnumerable нельзя считать повторяемым».

В Linq-To-Sql или Linq-To-Entities вы можете вызвать базу данных при каждом вызове IsNullOrEmpty.

0

Как @Marc Gravel, упомянутый в комментариях, «IEnumerable<T> не следует считать повторяемым». Предположим, что ваш источник IEnumerable создан из datareader. У вас есть только один шанс повторить его. Если вы воспользуетесь этой возможностью, просто убедитесь, что она пуста, вы больше не сможете получить доступ к записям. Возможно, вы хотели бы написать метод расширения (если необходимо) для IList, а не для IEnumerable.

public static bool IsNullOrEmpty<T>(this IList<T> source) 
{ 
    return source == null || source.Count == 0; 
} 
+1

Я хочу, чтобы C# и VB.NET имели «foreach» конструкты, которые могли бы принимать вещи, упорядоченные по счетчикам, а не только возможность принимать вещи с помощью метода «GetEnumerator». Вещи, которые могут быть прочитаны только один раз, должны быть перечисляющими, а не перечисляемыми. Это связано с неспособностью языка работать с первым, что им приходится притворяться последним. – supercat