这会多次调用 GetEnumerator() 吗?
Will this call GetEnumerator() More than Once?
在我们的代码库中,我们有一个数据访问层,它提供的方法类似于:
public IEnumerable<Foo> GetFoos()
{
var collection = new Collection<Foo>();
// ...call db
while (read results)
{
collection.Add(item);
}
return collection;
}
因此,虽然方法签名 return 是一个 IEnumerable,但在幕后,它创建了一个 Collection(已被枚举)。期望 IEnumerable 的此方法的使用者实际上会调用 GetEnumerator(),还是他们实际上会在不知不觉中使用 Collection?
IEnumerable<Foo> myFoos = GetFoos();
// will .Any() cause enumeration even though it's a Collection under the hood?
if (myFoos != null && myFoos.Any())
{
// ...
}
是的,它会一直调用 GetEnumerator()
。
我们可以通过检查 the implementation of Any()
on ReferenceSource.microsoft.com:
来验证这一点
public static bool Any<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) return true;
}
return false;
}
如果你关心性能,但又想限制消费者改变集合的能力,你可以考虑返回IReadOnlyCollection<T>
。这实际上只是一个 IEnumerable<T>
和一个 Count
属性。然后消费者可以检查 Count
属性,但除了枚举它之外不能做任何事情。 (除非他们开始做一些令人讨厌的事情,比如将其转换为原始集合类型...)
如果您想在这种情况下避免对集合进行枚举,您可以执行以下操作:
ICollection col = myFoos as ICollection;
bool hasItems = false;
if (col != null && col.Count > 0)
{
hasItems = true;
}
else
{
hasItems = (myFoos != null && myFoos.Any());
}
但是这可能比仅仅调用 .Any()
有更多的开销——无论你从检查 .Count
中获得的任何节省都可能被检查 myFoos
是否为 [=] 的成本所抵消14=] 并加载它。这样做的唯一好处是,如果出于某些其他原因,您想像 ICollection
一样对对象进行操作。你的另一个选择是让你的 GetFoos
函数 return 和 ICollection
开始......
在我们的代码库中,我们有一个数据访问层,它提供的方法类似于:
public IEnumerable<Foo> GetFoos()
{
var collection = new Collection<Foo>();
// ...call db
while (read results)
{
collection.Add(item);
}
return collection;
}
因此,虽然方法签名 return 是一个 IEnumerable,但在幕后,它创建了一个 Collection(已被枚举)。期望 IEnumerable 的此方法的使用者实际上会调用 GetEnumerator(),还是他们实际上会在不知不觉中使用 Collection?
IEnumerable<Foo> myFoos = GetFoos();
// will .Any() cause enumeration even though it's a Collection under the hood?
if (myFoos != null && myFoos.Any())
{
// ...
}
是的,它会一直调用 GetEnumerator()
。
我们可以通过检查 the implementation of Any()
on ReferenceSource.microsoft.com:
public static bool Any<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) return true;
}
return false;
}
如果你关心性能,但又想限制消费者改变集合的能力,你可以考虑返回IReadOnlyCollection<T>
。这实际上只是一个 IEnumerable<T>
和一个 Count
属性。然后消费者可以检查 Count
属性,但除了枚举它之外不能做任何事情。 (除非他们开始做一些令人讨厌的事情,比如将其转换为原始集合类型...)
如果您想在这种情况下避免对集合进行枚举,您可以执行以下操作:
ICollection col = myFoos as ICollection;
bool hasItems = false;
if (col != null && col.Count > 0)
{
hasItems = true;
}
else
{
hasItems = (myFoos != null && myFoos.Any());
}
但是这可能比仅仅调用 .Any()
有更多的开销——无论你从检查 .Count
中获得的任何节省都可能被检查 myFoos
是否为 [=] 的成本所抵消14=] 并加载它。这样做的唯一好处是,如果出于某些其他原因,您想像 ICollection
一样对对象进行操作。你的另一个选择是让你的 GetFoos
函数 return 和 ICollection
开始......