.net IEnumerable 是空的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3779817/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
IEnumerable is empty?
提问by cristobalito
I know it probably doesnt matter/affect performance for the most part but I hate the idea of getting an IEnumerableand doing .Count(). Is there a IsEmptyor NotEmptyor some function? (similar to stl empty())
我知道这在大多数情况下可能无关紧要/影响性能,但我讨厌获得IEnumerable并执行.Count(). 是否有一个IsEmpty或NotEmpty或一些功能?(类似于 stl empty())
回答by cristobalito
You want IEnumerable.Any()extension method (.Net Framework 3.5 and above). It avoids counting over the elements.
您需要IEnumerable.Any()扩展方法(.Net Framework 3.5 及更高版本)。它避免对元素进行计数。
回答by Artiom
if it is not generic than something like this
如果它不是像这样的通用
enumeration.Cast<object>().Any();
if it's generic, use extension of Enumerable as was said already
如果它是通用的,请使用已经说过的 Enumerable 的扩展
回答by nothrow
Without any need of LINQ, you can do following:
无需 LINQ,您可以执行以下操作:
bool IsEmpty(IEnumerable en)
{
foreach(var c in en) { return false; }
return true;
}
回答by Joe
You can use extension methods such as Any() or Count(). Count() is more costly than Any(), since it must execute the whole enumeration, as others have pointed out.
您可以使用扩展方法,例如 Any() 或 Count()。正如其他人指出的那样,Count() 比 Any() 成本更高,因为它必须执行整个枚举。
But in the case of lazy evaluation (e.g. a method that uses yield), either can be costly. For example, with the following IEnumerableimplementation, each call to Any or Count will incur the cost of a new roundtrip to the database:
但是在惰性求值的情况下(例如使用 yield 的方法),两者都可能代价高昂。例如,使用以下IEnumerable实现,每次调用 Any 或 Count 都会产生新的数据库往返成本:
IEnumerable<MyObject> GetMyObjects(...)
{
using(IDbConnection connection = ...)
{
using(IDataReader reader = ...)
{
while(reader.Read())
{
yield return GetMyObjectFromReader(reader);
}
}
}
}
I think the moral is:
我认为道德是:
If you only have an
IEnumerable<T>, and you want to do more than just enumerate it (e.g. use Count or Any), then consider first converting it to a List (extension method ToList). In this way you guarantee to only enumerate once.If you are designing an API that returns a collection, consider returning
ICollection<T>(or evenIList<T>) rather thanIEnumerable<T>as many people seem to recommend. By doing so you are strengthening your contract to guarantee no lazy evaluation (and therefore no multiple evaluation).
如果您只有一个
IEnumerable<T>,并且您想做的不仅仅是枚举它(例如使用 Count 或 Any),那么请考虑首先将其转换为 List(扩展方法 ToList)。通过这种方式,您可以保证只枚举一次。如果您正在设计一个返回集合的 API,请考虑返回
ICollection<T>(甚至IList<T>),而不是IEnumerable<T>像许多人推荐的那样。通过这样做,您正在加强您的合同以保证没有惰性评估(因此没有多重评估)。
Please note I am saying you should considerreturning a collection, not alwaysreturn a collection. As always there are trade-offs, as can be seen from the comments below.
请注意,我是说您应该考虑返回一个集合,而不是总是返回一个集合。与往常一样,权衡取舍,从下面的评论中可以看出。
@KeithS thinks you should never yield on a DataReader, and while I never say never, I'd say it's generally sound advice that a Data Access Layer should return an
ICollection<T>rather than a lazy-evaluatedIEnumerable<T>, for the reasons KeithS gives in his comment.@Bear Monkey notes that instantiating a List could be expensive in the above example if the database returns a large number of records. That's true too, and in some (probably rare) cases it may be appropriate to ignore @KeithS's advice and return a lazy-evaluated enumeration, provided the consumer is doing something that is not too time-consuming (e.g. generating some aggregate values).
@KeithS 认为你永远不应该在 DataReader 上让步,虽然我从不说永远,但我认为数据访问层应该返回一个
ICollection<T>而不是懒惰评估的IEnumerable<T>,这通常是合理的建议,原因是 KeithS 在他的评论中给出的原因。@Bear Monkey 指出,如果数据库返回大量记录,则在上面的示例中实例化 List 可能会很昂贵。这也是真的,并且在某些(可能很少见)的情况下,忽略@KeithS 的建议并返回延迟评估的枚举可能是合适的,前提是消费者正在做一些不太耗时的事情(例如生成一些聚合值)。
回答by Les
Keep in mind that IEnumerable is just an interface. The implementation behind it can be very different from class to class (consider Joe's example). The extension method IEnumerable.Any() has to be a generic approach and may not be what you want (performance wise). Yossarian suggests a means that should work for many classes, but if the underlying implementation does not use 'yield' you could still pay a price.
请记住,IEnumerable 只是一个接口。它背后的实现可能因类而异(考虑 Joe 的示例)。扩展方法 IEnumerable.Any() 必须是通用方法,可能不是您想要的(性能方面)。Yossarian 提出了一种应该适用于许多类的方法,但如果底层实现不使用“yield”,您仍然需要付出代价。
Generally, if you stick to collections or arrays wrapped in an IEnumerable interface, then Cristobalito and Yossarian probably have the best answers. My guess is the built-in .Any() ext method does what Yossarian recommends.
通常,如果您坚持使用 IEnumerable 接口包装的集合或数组,那么 Cristobalito 和 Yossarian 可能有最好的答案。我的猜测是内置的 .Any() ext 方法执行 Yossarian 的建议。
回答by Justin Niessner
On IEnumerableor IEnumerable<T>, no.
在IEnumerable或IEnumerable<T>,没有。
But it really doesn't make much sense. If a collection is empty and you try to iterate over it using IEnumerable, the call to IEnumerator.MoveNext()will simply return false at no performance cost.
但这真的没有多大意义。如果一个集合为空并且您尝试使用 对其进行迭代IEnumerable,则调用IEnumerator.MoveNext()将简单地返回 false 而不会产生性能成本。
回答by Bobby
I don't think so, that's what Countis for. Besides, what will be faster:
我不这么认为,这就是原因Count。此外,什么会更快:
- Accessing a Property and retrieving a stored
Integer - Accessing a Property and retrieving a stored
Boolean
- 访问属性并检索存储的
Integer - 访问属性并检索存储的
Boolean
回答by Jonathan Parker
You can also write your own Count extension method overloads like so:
您还可以编写自己的 Count 扩展方法重载,如下所示:
/// <summary>
/// Count is at least the minimum specified.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="min"></param>
/// <returns></returns>
public static bool Count<TSource>(this IEnumerable<TSource> source, int min)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return source.Count(min, int.MaxValue);
}
/// <summary>
/// Count is between the given min and max values
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static bool Count<TSource>(this IEnumerable<TSource> source, int min, int max)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (min <= 0)
{
throw new ArgumentOutOfRangeException("min", "min must be a non-zero positive number");
}
if (max <= 0)
{
throw new ArgumentOutOfRangeException("max", "max must be a non-zero positive number");
}
if (min >= max)
throw new ArgumentOutOfRangeException("min and max", "min must be lest than max");
var isCollection = source as ICollection<TSource>;
if (isCollection != null)
return isCollection.Count >= min && isCollection.Count <= max;
var count = 0;
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
count++;
if (count >= min && count <= max)
return true;
}
}
return false;
}
回答by ali
Use Enumerable.Empty() which rather than IEnumerable.Any() will prevent ending up having null list.
使用 Enumerable.Empty() 而不是 IEnumerable.Any() 将防止最终出现空列表。

