Answers:
IEnumerable
不支持这一点。这是设计使然。IEnumerable
使用惰性评估来获取您需要的元素,然后再使用它们。
如果您想知道项目的数量而不需要遍历它们,可以使用ICollection<T>
,它具有一个Count
属性。
的System.Linq.Enumerable.Count
扩展方法IEnumerable<T>
具有以下实现:
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;
因此,它尝试强制转换为ICollection<T>
具有Count
属性的,并在可能的情况下使用它。否则进行迭代。
因此,最好的选择是Count()
在IEnumerable<T>
对象上使用扩展方法,因为那样会获得最佳性能。
ICollection<T>
。
T
上IEnumerator<T> enumerator = source.GetEnumerator()
,只需你可以做到这一点:IEnumerator enumerator = source.GetEnumerator()
与应努力!
IEnumerable<T>
继承IDisposable
,使using
语句可以自动处理它。IEnumerable
才不是。因此,GetEnumerator
无论您采用哪种方式打电话,您都应该以var d = e as IDisposable; if (d != null) d.Dispose();
只需添加一些额外的信息:
该Count()
扩展并不总是迭代。考虑将Linq转换为Sql,其中将计数发送到数据库,但是它不带回所有行,而是发出Sql Count()
命令并返回该结果。
另外,编译器(或运行时)足够聪明,Count()
如果有的话,它将调用objects 方法。因此,它并不像其他响应者所说的那样,完全无知并总是为了计数元素而反复进行。
在许多情况下,程序员只是if( enumerable.Count != 0 )
使用Any()
扩展方法进行检查,因为if( enumerable.Any() )
linq的惰性评估会更有效,因为一旦确定有任何元素,它就会短路。它也更具可读性
.Count
属性,因为它始终知道其大小。查询collection.Count
时没有其他计算,它仅返回已知的计数。同样的Array.length
,据我所知。但是,使用.Any()
获取源的枚举数,using (IEnumerator<TSource> enumerator = source.GetEnumerator())
如果可以,则返回true enumerator.MoveNext()
。对于collections if(collection.Count > 0)
,arrays if(array.length > 0)
和on enumerables而言if(collection.Any())
。
IQueryably<T>
为a IEnumerable<T>
,则不会发出sql计数。当我写这篇文章时,Linq to Sql是新的。我想我只是在努力使用,Any()
因为对于枚举,集合和sql而言,它的效率和可读性要高得多(通常)。感谢您改善答案。
我的一个朋友有一系列博客文章,这些插图说明了为什么您不能这样做。他创建了一个返回IEnumerable的函数,该函数每次迭代都返回下一个素数,一直到ulong.MaxValue
,直到您要求下一个项目才被计算。快速弹出的问题:退回多少物品?
这些是帖子,但篇幅较长:
EnumerableFeatures
对象)将不需要枚举器做任何困难的事情,而是能够提出这样的问题(以及诸如“您可以保证...总是返回相同的项目序列”,“您是否可以安全地使用不应更改基础集合的代码”等)将非常有用。
set yield options
声明或类似的内容来支持它。如果设计合理,则IEnhancedEnumerator
可以消除很多“防御性” ToArray
或ToList
呼叫,从而使LINQ之类的东西更加有用,尤其是...
Enumerable.Concat
通常会将对自己有很多了解的大型收藏与不了解的小收藏结合起来。
IEnumerable在不进行迭代的情况下无法计数。
在“正常”情况下,实现IEnumerable或IEnumerable <T>的类(例如List <T>)可能会通过返回List <T> .Count属性来实现Count方法。但是,Count方法实际上并不是在IEnumerable <T>或IEnumerable接口上定义的方法。(实际上,唯一的一个就是GetEnumerator。)这意味着无法为其提供特定于类的实现。
Count是一个扩展方法,在静态类Enumerable上定义。这意味着可以在IEnumerable <T>派生类的任何实例上调用它,而不管该类的实现如何。但这也意味着它是在任何这些类外部的一个地方实现的。当然,这意味着必须以完全独立于此类内部的方式来实现它。这种唯一的计数方法是通过迭代。
或者,您可以执行以下操作:
Tables.ToList<string>().Count;
不,不一般。使用枚举的一点是,枚举中的对象的实际集合是未知的(预先知道,甚至根本不知道)。
您可以使用System.Linq。
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());
}
}
您将得到结果“ 2”。
除了您提出的紧迫问题(已完全否定回答)之外,如果您希望在处理枚举的同时报告进度,则可能需要查看我的博客文章“ Linq查询期间的进度报告”。
它可以让您做到这一点:
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += (sender, e) =>
{
// pretend we have a collection of
// items to process
var items = 1.To(1000);
items
.WithProgressReporting(progress => worker.ReportProgress(progress))
.ForEach(item => Thread.Sleep(10)); // simulate some real work
};
我在方法内部使用了这种方法来检查传入的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 ... }
。
这取决于.Net的版本以及IEnumerable对象的实现。Microsoft已修复IEnumerable.Count方法以检查实现,并使用ICollection.Count或ICollection <TSource> .Count,请在此处查看详细信息https://connect.microsoft.com/VisualStudio/feedback/details/454130
下面是Ildasm提供的System.Core的MSIL,System.Linq驻留在其中。
.method public hidebysig static int32 Count<TSource>(class
[mscorlib]System.Collections.Generic.IEnumerable`1<!!TSource> source) cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
// Code size 85 (0x55)
.maxstack 2
.locals init (class [mscorlib]System.Collections.Generic.ICollection`1<!!TSource> V_0,
class [mscorlib]System.Collections.ICollection V_1,
int32 V_2,
class [mscorlib]System.Collections.Generic.IEnumerator`1<!!TSource> V_3)
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000e
IL_0003: ldstr "source"
IL_0008: call class [mscorlib]System.Exception System.Linq.Error::ArgumentNull(string)
IL_000d: throw
IL_000e: ldarg.0
IL_000f: isinst class [mscorlib]System.Collections.Generic.ICollection`1<!!TSource>
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: brfalse.s IL_001f
IL_0018: ldloc.0
IL_0019: callvirt instance int32 class [mscorlib]System.Collections.Generic.ICollection`1<!!TSource>::get_Count()
IL_001e: ret
IL_001f: ldarg.0
IL_0020: isinst [mscorlib]System.Collections.ICollection
IL_0025: stloc.1
IL_0026: ldloc.1
IL_0027: brfalse.s IL_0030
IL_0029: ldloc.1
IL_002a: callvirt instance int32 [mscorlib]System.Collections.ICollection::get_Count()
IL_002f: ret
IL_0030: ldc.i4.0
IL_0031: stloc.2
IL_0032: ldarg.0
IL_0033: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<!!TSource>::GetEnumerator()
IL_0038: stloc.3
.try
{
IL_0039: br.s IL_003f
IL_003b: ldloc.2
IL_003c: ldc.i4.1
IL_003d: add.ovf
IL_003e: stloc.2
IL_003f: ldloc.3
IL_0040: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0045: brtrue.s IL_003b
IL_0047: leave.s IL_0053
} // end .try
finally
{
IL_0049: ldloc.3
IL_004a: brfalse.s IL_0052
IL_004c: ldloc.3
IL_004d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0052: endfinally
} // end handler
IL_0053: ldloc.2
IL_0054: ret
} // end of method Enumerable::Count
IEnumerable.Count()函数的结果可能是错误的。这是一个非常简单的示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var test = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 };
var result = test.Split(7);
int cnt = 0;
foreach (IEnumerable<int> chunk in result)
{
cnt = chunk.Count();
Console.WriteLine(cnt);
}
cnt = result.Count();
Console.WriteLine(cnt);
Console.ReadLine();
}
}
static class LinqExt
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int chunkLength)
{
if (chunkLength <= 0)
throw new ArgumentOutOfRangeException("chunkLength", "chunkLength must be greater than 0");
IEnumerable<T> result = null;
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
result = GetChunk(enumerator, chunkLength);
yield return result;
}
}
}
static IEnumerable<T> GetChunk<T>(IEnumerator<T> source, int chunkLength)
{
int x = chunkLength;
do
yield return source.Current;
while (--x > 0 && source.MoveNext());
}
}
}
结果必须为(7,7,3,3),但实际结果为(7,7,3,17)
我发现最好的方法是通过将其转换为列表来计数。
IEnumerable<T> enumList = ReturnFromSomeFunction();
int count = new List<T>(enumList).Count;
它可能不会产生最佳性能,但是您可以使用LINQ来计数IEnumerable中的元素:
public int GetEnumerableCount(IEnumerable Enumerable)
{
return (from object Item in Enumerable
select Item).Count();
}
我使用IEnum<string>.ToArray<string>().Length
,并且效果很好。
IEnum<string>.Count();
“?