C#List <t> vs IEnumerable <t>性能问题</t> </t>

时间:2009-07-31 09:15:02

标签: c# performance list ienumerable

嗨,假设这两种方法:

private List<IObjectProvider> GetProviderForType(Type type)
        {
            List<IObjectProvider> returnValue = new List<IObjectProvider>();

            foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
            {
                if ((provider.Key.IsAssignableFrom(type) ||
                    type.IsAssignableFrom(provider.Key)) &&
                    provider.Value.SupportsType(type))
                {
                    returnValue.Add(provider.Value);
                }
            }
            return returnValue;
        }

private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
        {
            foreach (KeyValuePair<Type, IObjectProvider> provider in _objectProviders)
                if ((provider.Key.IsAssignableFrom(type) ||
                    type.IsAssignableFrom(provider.Key)) &&
                    provider.Value.SupportsType(type))

                    yield return provider.Value;              
        }

哪一个更快?当我查看第一种方法时,我看到内存是为List分配的,我认为不需要它。 IEnumerable 方法对我来说似乎更快。

例如,假设你打电话

int a = GetProviderForType(myType).Count;
int b = GetProviderForType1(myType).Count();

现在,另一个问题是,这两个之间是否有性能差异?

您怎么看?

4 个答案:

答案 0 :(得分:30)

在这种特殊情况下,使用IEnumerable<T>表单会更有效率,因为需要知道计数。如果你不需要,那么存储数据,调整缓冲区大小等没有意义。

如果您因任何原因需要再次使用结果,List<T>表格会更有效。

请注意,Count()扩展方法和Count属性对List<T>都有效,因为Count()的实现会检查目标序列是否实现{{}如果是,请使用ICollection<T>属性。

另一个应该是更多效率的选项(尽管只是)只会调用带有委托的Count的重载:

Count

这将避免private int GetProviderCount(Type type) { return _objectProviders.Count(provider => (provider.Key.IsAssignableFrom(type) || type.IsAssignableFrom(provider.Key)) && provider.Value.SupportsType(type)); } Where条款带来的额外级别的间接。

(正如Marc所说,对于少量数据,性能差异无论如何都可能微不足道。)

答案 1 :(得分:4)

对此类问题的准确答案可能会因许多因素而异,并且可能会随着CLR的发展而进一步变化。确定的唯一方法是测量它 - 并记住,如果与显示的操作相比差异很小,那么你应该选择最易读,可维护的编写方式。

在这方面,您可能还想尝试:

private IEnumerable<IObjectProvider> GetProviderForType1(Type type)
{
    return _objectProviders.Where(provider => 
                  provider.Key.IsAssignableFrom(type) ||
                  type.IsAssignableFrom(provider.Key)) &&
                  provider.Value.SupportsType(type))
                           .Select(p => p.Value);
}

如果要将结果“快照”到列表中,还可以返回IEnumerable<T>然后使用ToList扩展方法,为自己提供很大的灵活性。如果需要多次检查,这将避免重复评估代码以生成列表。

答案 2 :(得分:4)

这个问题的一个重要部分是“数据有多大”?多少行...

对于少量数据,列表很好 - 分配足够大的列表需要花费的时间可以忽略不计,并且不会多次调整大小(没有,如果你能告诉它有多大的话)。< / p>

但是,这不会扩展到庞大的数据量;您的提供商似乎不太可能支持数以千计的接口,因此我不会说它是必要来使用此模型 - 但它不会造成太大的伤害。

当然,您也可以使用LINQ:

return from provider in _objectProviders
       where provider.Key.IsAssignableFrom(type) ...
       select provider.Value;

这也是推迟的yield方法......

答案 3 :(得分:2)

IEnumerable和IList之间的主要区别:

IEnumerable的: 实现MoveNext,重置,获取当前方法并返回一类IEnumerator以进行迭代     通过记录。

IList:暴露IEnumerable接口以及它也是非泛型对象的集合,可以通过索引访问所以IEnumerable + ICollection(操作数据)和添加,删除,插入(在特定的索引处)都是有用的IList实施的方法。

在查看你的Code In My Opinion后,IEnumerable更有效,但如果你想对数据进行一些操作,返回列表也很有用,如果你只想迭代数据,那么IEnumerable是更好的。