繁体   English   中英

这会多次调用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;
}

因此,虽然方法签名在内部返回了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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM