我知道这可能在大多数情况下并不影响性能,但我讨厌获取一个 IEnumerable
并执行 .Count()
的想法。是否有一个类似于 STL 的 empty()
函数的 IsEmpty
或 NotEmpty
函数?
我知道这可能在大多数情况下并不影响性能,但我讨厌获取一个 IEnumerable
并执行 .Count()
的想法。是否有一个类似于 STL 的 empty()
函数的 IsEmpty
或 NotEmpty
函数?
您需要使用IEnumerable.Any()扩展方法(.Net Framework 3.5及以上版本)。它避免了对元素进行计数。
如果它不是通用的,那么就像这样
enumeration.Cast<object>().Any();
如果它是通用的,就像已经说过的那样,使用Enumerable的扩展。
无需使用LINQ,您可以进行以下操作:
bool IsEmpty(IEnumerable en)
{
foreach(var c in en) { return false; }
return true;
}
Any()
函数基本相同。 - Rubenforeach
创建和处理的iterator(IEnumerator);您肯定不想处理IEnumerable本身-您的调用者可能仍然需要它。 :) - ToolmakerSteveIEnumerable<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 上使用 yield,虽然我从不说永远,但我会说通常一个数据访问层应该返回一个 ICollection<T>
而不是一个延迟评估的 IEnumerable<T>
,原因就像 KeithS 在他的评论中给出的那样。
@Bear Monkey 指出,在上面的示例中实例化 List 可能是昂贵的,如果数据库返回大量记录,则这也是正确的。在某些(可能很少见)情况下,忽略 @KeithS 的建议并返回延迟评估的枚举可能是合适的,前提是消费者正在执行一些不太耗时的操作(例如生成一些聚合值)。
你也可以编写自己的 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;
}