2008-09-22 4 views
9

Я пытаюсь найти наиболее многоразовый, но элегантный, фрагмент кода, который можно определить, если IEnumerable. В идеале это должна быть функция, которую я могу вызвать абсолютно в любое время, когда мне нужно указать, является ли IEnumerable пустым.Что такое твердый, элегантный, многоразовый фрагмент кода для определения, является ли IEnumerable пустым, в .NET?

Хотя я разработал ответ для .NET 3.5, который до сих пор хорошо работал для меня, моя нынешняя мысль заключается в том, что нет идеального ответа, поскольку IEnumerable может инкапсулировать коллекцию (или очередь итераторов), которая модифицирует основные результаты, которые он выполняет, и которые могут вызвать проблемы. Однако это также будет препятствием для внедрения IEnumerable.Count(), и это не помешало MS предоставить его.

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

Редактировать: Вау, я не могу поверить, что не знал об IEnumerable.Any. Я знал, что он существует, но никогда не потрудился проверить, что он сделал. Пусть это будет уроком. Прочтите документацию. Просто потому, что имя метода не означает, что оно делает то, что вы хотите, не означает, что оно не делает то, что вы хотите.

ответ

22
!enumerable.Any() 

Будет пытаться захватить только первый элемент.

Чтобы узнать, как это работает, любой определяет, будет ли какой-либо из компонентов IEnumerable соответствовать заданной функции, если ни один не указан, то любой компонент будет успешным, то есть функция вернет true, если элемент существует в перечислимый.

+0

Ничего себе .... не могу поверить, что я не знал об этом. Благодаря! – 2008-09-22 20:24:37

+2

Это новое в .Net 3.5 – Keith 2008-09-22 20:41:02

2

Для .net 1/2:

IEnumerator e; 
try 
{ 
    e = enumerable.GetEnumerator(); 
    return e.MoveNext(); 
} 
finally 
{ 
    if (e is IDisposable) 
     e.Dispose(); 
} 

Или, с обобщениями:

using (IEnumerator<T> e = enumerable.GetEnumerator()) 
{ 
    return e.MoveNext(); 
} 
0

Одна вещь, чтобы быть осторожным с любым из этих методов является то, что не все Перечисления могут быть rolled- назад, например, все реализации System.Data.IDataReader могут выполняться только один раз.

В этих случаях у вас действительно нет стоимости в цикле foreach, если вы считаете, что он может даже не зацикливаться один раз.

2

Вы правы, что нет идеального ответа. IEnumerable поддерживает только итерацию и не гарантирует повторения перечисления. Вы не можете узнать, содержит ли перечисление элементы без вызова MoveNext хотя бы один раз, и как только вы это сделаете, вы не можете гарантировать повторное использование перечисления: допустимо для IEnumerable.Reset выбрасывать исключение NotSupportedException. От http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx:

«Метод сброса предназначен для обеспечения совместимости COM. Это необязательно необходимо реализовать, вместо этого разработчик может просто выбросить исключение NotSupportedException».

Методы расширения, такие как IEnumerable <T> .Count и IEnumerable <T> .Any нужно вызвать MoveNext под крышки. Полезные обертки, но не избегайте того факта, что в редких случаях, когда перечисление не поддерживает Reset, у вас может быть проблема.