[英]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;
}
因此,虽然方法签名在内部返回了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()
。
我们可以通过检查ReferenceSource.microsoft.com上Any()
的实现来验证这一点:
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
是否为ICollection
并加载它的成本所抵消。 这样做的唯一好处是,如果您出于某种其他原因而想像该对象是ICollection
一样对它进行操作。 您的另一个选择是让您的GetFoos
函数返回一个ICollection
开头...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.