private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
假设我想在迭代过程中编写类似于处理 #n of #m 的内容。
在我的主要迭代之前,有没有一种方法可以找出 m 的值?
希望我表达清楚了。
private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
假设我想在迭代过程中编写类似于处理 #n of #m 的内容。
在我的主要迭代之前,有没有一种方法可以找出 m 的值?
希望我表达清楚了。
IEnumerable
不支持此操作。这是有意设计的。 IEnumerable
采用惰性求值的方式,在你需要元素时才获取所要求的元素。
如果你想知道项目数量而不需要遍历它们,可以使用 ICollection<T>
,它有一个 Count
属性。
IEnumerable<T>
上的System.Linq.Enumerable.Count
扩展方法具有以下实现:
ICollection<T> c = source as ICollection<TSource>;
if (c != null)
return c.Count;
int result = 0;
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
result++;
}
return result;
所以它尝试将其转换为拥有Count
属性的ICollection<T>
,如果可能的话就使用它。否则就进行迭代。IEnumerable<T>
对象上使用Count()
扩展方法,这样可以获得最佳性能。ICollection<T>
这一点非常有趣。 - Oscar MederosIEnumerable<T>
继承了 IDisposable
接口,这使得使用 using
语句可以自动释放资源。但是 IEnumerable
没有继承 IDisposable
接口。因此,如果你以任何一种方式调用 GetEnumerator
,最好在结束时加上 var d = e as IDisposable; if (d != null) d.Dispose();
。 - Daniel Earwicker仅添加一些额外的信息:
Count()
扩展方法并不总是迭代。考虑使用 Linq to Sql 的情况,其中计数会发送到数据库,但是它不会将所有行都带回来,而是发出 Sql Count()
命令并返回结果。
此外,编译器(或运行时)足够聪明,如果对象具有Count()
方法,则会调用该方法。因此,与其他答复者所说的完全无知并始终迭代以计算元素数量不同。
在许多情况下,程序员只需使用 Any()
扩展方法来检查if( enumerable.Count != 0 )
,例如if( enumerable.Any() )
与 Linq 的惰性求值相比更加高效,一旦确定是否存在任何元素,它就可以进行短路运算。同时也更易读。
.Count
属性,因为它始终知道其大小。在查询 collection.Count
时,没有额外计算,它只是返回已知的计数。据我所知,对于 Array.length
也是如此。但是,.Any()
使用 using (IEnumerator<TSource> enumerator = source.GetEnumerator())
获取源的枚举器,并在可以执行 enumerator.MoveNext()
时返回 true。对于集合: if(collection.Count > 0)
,数组: if(array.length > 0)
,对于可枚举的对象则使用 if(collection.Any())
。 - NopeIQueryably<T>
显式转换为IEnumerable<T>
,它将不会发出SQL计数。当我写这篇文章时,Linq to Sql还很新;我认为我只是在推动使用Any()
,因为对于可枚举、集合和SQL来说,它更有效率和易读(总体而言)。感谢您改进了答案。 - Robert Paulson或者你可以尝试以下方法:
Tables.ToList<string>().Count;
我的一个朋友写了一系列博客文章,为什么你不能这样做提供了一个例子。他创建了一个函数,返回一个IEnumerable序列,每次迭代都会返回下一个质数,一直到ulong.MaxValue
,并且直到你请求它时才计算下一个项。快速问题:会返回多少项?
这里是这些博客文章,但它们有点长:
Enumerable.Concat
来合并一个大集合和一个不知道自己很多信息的小集合的情况下。 - supercat使用IEnumerable无法进行计数而不迭代。
在“正常”情况下,实现IEnumerable或IEnumerable<T>的类(例如List<T>)可以通过返回List<T>.Count属性来实现Count方法。 但是,Count方法实际上不是在IEnumerable<T>或IEnumerable接口上定义的方法。(实际上,在这两个接口中仅有GetEnumerator方法被定义。)这意味着不能为其提供特定于类的实现。
相反,Count是一个扩展方法,定义在静态类Enumerable中。这意味着它可以在任何派生自IEnumerable<T>的类的任何实例上调用,而与该类的实现无关。但这也意味着它是在一个单独的位置实现的,与所有这些类的内部完全独立。当然,这意味着它必须以完全独立于这些类内部的方式实现计数。唯一的这种方式就是通过迭代。
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
private IEnumerable<string> Tables
{
get {
yield return "Foo";
yield return "Bar";
}
}
static void Main()
{
var x = new Test();
Console.WriteLine(x.Tables.Count());
}
}
我在一个方法内使用了这种方式来检查传入的IEnumberable
内容。
if( iEnum.Cast<Object>().Count() > 0)
{
}
在像这样的方法内部:
GetDataTable(IEnumberable iEnum)
{
if (iEnum != null && iEnum.Cast<Object>().Count() > 0) //--- proceed further
}
bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }
。 - ToolmakerSteve... { if (!hasContents) { hasContents = true; ..one time code..; } else { ..code for all but first time..} ...}"
诚然,这比您简单的方法更加繁琐,因为一次性代码需要放在if语句内,在循环之前,但是如果".Count()"的成本是一个问题,那么这就是正确的方式。 - ToolmakerSteve