List<T>()
中System.Collections.Generic
的默认容量为0。
说我有一个功能
private IEnumerable<SomeType> DoStuff(IEnumerable<OtherType> e)
{
var list = new List<SomeType>();
foreach (var elem in e)
{
list.Add(new SomeType
{
SomeProperty = elem.OtherProperty
});
}
return list;
}
我在运行循环之前设置了list
的大小,如下所示:
private IEnumerable<SomeType> DoStuff(IEnumerable<OtherType> e)
{
var list = new List<SomeType>(e.Count());
foreach (var elem in e)
{
list.Add(new SomeType
{
SomeProperty = elem.OtherProperty
});
}
return list;
}
它是否会影响运行时间,或者没有理由这样做,因为e
的大小是动态的&#39;?
答案 0 :(得分:5)
这取决于IEnumerable<OtherType> e
...
e.Count()
可以枚举e
只计算它......如果e
是对数据库的查询,它将被执行两次,一次为e.Count()
,一次为{ {1}} ......慢!
如果foreach
是e
或List<>
或实施OtherType[]
的其他类型,则ICollection<>
使用Count()
属性,它没有枚举Count
。
请注意,对于这个简单的案例,您可以:
IEnumerable<>
现在......正如@Jonathan注意到的那样,你正在返回一个return e.Select(x => new SomeType { SomeProperty = x.OtherProperty })
.ToList();
,所以你可以:
IEnumerable<>
并且幸福快乐......或者你可以
return e.Select(x => new SomeType { SomeProperty = x.OtherProperty });
(这几乎等同于执行private IEnumerable<SomeType> DoStuff(IEnumerable<OtherType> e)
{
foreach (var elem in e)
{
yield return new SomeType
{
SomeProperty = elem.OtherProperty
};
}
}
,但是如果你有一个复杂的表达式来转换元素,那么使用Select
会变得很麻烦)
或者,如果你真的想创建一个Select
并在可能的情况下加以预测:
List<>
与往常一样,请记住,不应多次枚举ICollection<T> c = e as ICollection<T>;
int count = c != null ? c.Count : 0;
var list = new List<SomeType>(count);
,除非您确实确定
IEnumerable<>
或其他伪装集合,因此数据已经存在,并且多次枚举它没有问题或
List<>
时都会从头开始重建,但费用可以忽略不计。答案 1 :(得分:3)
不要这样做。这样,您就可以对序列e
进行两次枚举:一次在foreach
内,一次到{{1} }。
为Count()
构造函数提供容量背后的想法是防止不必要的数组分配。该列表动态增长,这意味着它会在必要时分配一个新数组,该数组的长度是其两倍。如果它预先知道所需的容量,List<T>
可以从一开始就分配一个正确大小的数组。
关于的一般建议是否会影响运行时间:衡量,不要假设。你可以在这里保存数组分配,但是你可能会慢一点,因为你不止一次地迭代序列。