C#List< T> vs IEnumerable< T>表现问题
-
06-07-2019 - |
题
嗨,假设这两种方法:
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();
现在,另一个问题是,这两个之间是否有性能差异?
您怎么看?
解决方案
在这种特殊情况下,使用 IEnumerable&lt; T&gt;
表单会更有效率,因为仅需要知道计数。如果你不需要,那么存储数据,调整缓冲区大小等没有意义。
如果您因任何原因需要再次使用结果, List&lt; T&gt;
表单会更有效。
请注意, Count()
扩展方法和 Count
属性对于 List&lt; T&gt;
都是有效的< code> Count()检查目标序列是否实现 ICollection&lt; T&gt;
,如果是,则使用 Count
属性。
另一个应该是更多效率的选项(尽管只是)只是调用 Count
的重载,它带有一个委托:
private int GetProviderCount(Type type)
{
return _objectProviders.Count(provider =>
(provider.Key.IsAssignableFrom(type)
|| type.IsAssignableFrom(provider.Key))
&& provider.Value.SupportsType(type));
}
这将避免 Where
和 Select
子句带来的额外级别的间接。
(正如Marc所说,对于少量数据,性能差异无论如何都可能微不足道。)
其他提示
对此类问题的准确答案可能会因许多因素而异,并且可能会随着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&lt; T&gt;
然后使用 ToList
扩展方法给自己很大的灵活性。将结果放入列表中。如果需要多次检查,这将避免重复评估代码以生成列表。
这个问题的一个重要部分是“数据有多大”?多少行...
对于少量数据,列表很好 - 分配足够大的列表需要花费的时间可以忽略不计,并且不会多次调整大小(没有,如果你能告诉它有多大的话)。
但是,这不会扩展到庞大的数据量;您的提供商似乎不太可能支持数以千计的接口,因此我不会说它是必要来使用此模型 - 但它不会造成太大的伤害。
当然,您也可以使用LINQ:
return from provider in _objectProviders
where provider.Key.IsAssignableFrom(type) ...
select provider.Value;
这也是隐藏的 yield
方法......
IEnumerable和IList之间的主要区别:
IEnumerable的: 实现MoveNext,重置,获取当前方法并返回一类IEnumerator以进行迭代 通过记录。
IList:暴露IEnumerable接口以及它也是非泛型对象的集合,可以通过索引访问所以IEnumerable + ICollection(操作数据)和添加,删除,插入(在特定的索引)是有用的IList实施的方法。在查看你的Code In My Opinion后,IEnumerable效率更高,但是如果你想对数据进行一些操作,返回列表也很有用,如果你只想迭代数据,那么IEnumerable是更好的。