我知道在大多数情况下它可能无关紧要/影响性能,但我讨厌获得IEnumerable
和做.Count()
的想法。有IsEmpty
或NotEmpty
或某些功能吗? (类似于stl empty())
答案 0 :(得分:74)
您需要IEnumerable.Any()扩展方法(.Net Framework 3.5及更高版本)。它避免了对元素的计数。
答案 1 :(得分:15)
如果它不是通用的,那么
enumeration.Cast<object>().Any();
如果它是通用的,请按照已经说过的那样使用Enumerable的扩展
答案 2 :(得分:8)
无需任何LINQ,您可以执行以下操作:
bool IsEmpty(IEnumerable en)
{
foreach(var c in en) { return false; }
return true;
}
答案 3 :(得分:3)
您可以使用Any()或Count()等扩展方法。 Count()比Any()更昂贵,因为它必须执行整个枚举,正如其他人所指出的那样。
但是在惰性评估的情况下(例如使用产量的方法),要么成本高昂。例如,使用以下IEnumerable
实现,每次调用Any或Count都会产生新的数据包往返的成本:
IEnumerable<MyObject> GetMyObjects(...)
{
using(IDbConnection connection = ...)
{
using(IDataReader reader = ...)
{
while(reader.Read())
{
yield return GetMyObjectFromReader(reader);
}
}
}
}
我认为道德是:
如果您只有IEnumerable<T>
,并且您想做的不仅仅是枚举它(例如使用Count或Any),那么请考虑先将其转换为List(扩展方法ToList)。这样你就可以保证只枚举一次。
如果您正在设计一个返回集合的API,请考虑返回ICollection<T>
(甚至IList<T>
)而不是IEnumerable<T>
,因为很多人似乎都建议这样做。通过这样做,您可以加强合同,以保证不进行惰性评估(因此无需进行多重评估)。
请注意我说你应该考虑返回一个集合,而不是总是返回一个集合。一如既往权衡取舍,可以从下面的评论中看出。
@KeithS认为你永远不应该屈服于DataReader,虽然我永远不会说永远,但我会说一般来说,数据访问层应该返回ICollection<T>
而不是懒惰的建议由于KeithS在评论中给出的原因,对IEnumerable<T>
进行了评估。
@Bear Monkey指出,如果数据库返回大量记录,在上面的示例中实例化List可能会很昂贵。这也是正确的,在一些(可能是罕见的)情况下,忽略@ KeithS的建议并返回惰性评估的枚举可能是适当的,前提是消费者正在做一些不太耗时的事情(例如生成一些聚合值)。
答案 4 :(得分:2)
请记住,IEnumerable只是一个界面。它背后的实现可能因类而异(考虑Joe的例子)。扩展方法IEnumerable.Any()必须是通用方法,可能不是您想要的(性能明智)。 Yossarian建议一种适用于许多类的方法,但如果底层实现不使用'yield',你仍然可以付出代价。
通常,如果您坚持使用IEnumerable接口中包含的集合或数组,那么Cristobalito和Yossarian可能会得到最好的答案。我的猜测是内置的.Any()ext方法做了约塞连推荐的方法。
答案 5 :(得分:1)
在IEnumerable
或IEnumerable<T>
上,否。
但它确实没有多大意义。如果某个集合为空,并且您尝试使用IEnumerable
对其进行迭代,则对IEnumerator.MoveNext()
的调用只会返回false,而无需支付任何性能费用。
答案 6 :(得分:0)
我不这么认为,这就是Count
的用途。此外,什么会更快:
Integer
Boolean
答案 7 :(得分:0)
您也可以编写自己的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;
}
答案 8 :(得分:-1)
使用Enumerable.Empty()而不是IEnumerable.Any()将阻止最终有空列表。