我只想到造型和性能。以前我曾经写过类似的东西,
var strings = new List<string> { "a", "b", "c" };
var ints = new List<int> { 1, 2, 3};
但现在我更倾向于喜欢这种风格,
var strings = new [] { "a", "b", "c" }.ToList();
var ints = new [] { 1, 2, 3}.ToList();
我更喜欢第二种风格,但现在正在考虑 - 是否真的值得这样写,或者它不是那么有效并且需要更多操作?
答案 0 :(得分:42)
我不赞同Darin:他们在性能方面 不等同。后一版本必须创建一个新数组,然后ToList
将其复制到新列表中。集合初始化程序版本等同于:
var tmp = new List<int>();
tmp.Add(1);
tmp.Add(2);
tmp.Add(3);
var ints = tmp;
假设列表以足够大的缓冲区开始,不需要任何进一步的分配 - 尽管将涉及一些方法调用。如果您为非常大型项目执行此操作,那么它将需要更多分配而不是ToList
版本,因为它会在项目进行时复制项目
性能差异 可能是微不足道的,但它是非零的(并且明显在任何一个方向上都更好 - 数组版本中的调用次数较少,但是更多分配)。
除非你有理由怀疑差异是显着的,否则我会更专注于风格而不是表现,在这种情况下你应该衡量而不仅仅是猜测。
就我个人而言,我更喜欢第一种形式 - 我认为从一开始就使用列表会更清楚。另一种选择是编写自己的静态类:
public static class Lists
{
public static List<T> Of<T>(T item0)
{
return new List<T> { item0 };
}
public static List<T> Of<T>(T item0, T item1)
{
return new List<T> { item0, item1 };
}
public static List<T> Of<T>(T item0, T item1, T item2)
{
return new List<T> { item0, item1, item2 };
}
... as many times as you really care about, then ...
public static List<T> Of<T>(params T[] items)
{
return items.ToList();
}
}
然后你可以写:
var ints = Lists.Of(1);
var ints = Lists.Of(1, 2, 3);
var ints = Lists.Of(1, 2, 3, 5, 6, 7, 8); // Use the params version
这仍然表明您正在使用列表,但利用了类型推断。
你可能会认为它有点过分:)
答案 1 :(得分:13)
从绩效角度撇开两者之间的差异,前者表达了你想要以更好的方式实现的目标。
考虑用英语表达代码:
声明包含这些内容的字符串列表
和
声明包含这些内容的字符串数组,然后将其转换为字符串列表
对我来说,第一个似乎更自然。虽然我承认第二个可能对你更好。
答案 2 :(得分:7)
示例1(var ints = new List {1,2,3};):提供31.5%的开销(Eumerable.ToList),List.Add()导致8.7%的开销。
例如2:在List.ctor上产生11.8%的开销,在确保容量时产生5%的开销。
(Red Gate ANTS Performance Profiler的结果)
你可以看到var ints = new List {1,2,3};通过反汇编执行更多操作
var intsx = new[] {1, 2, 3}.ToList();
0000003f mov edx,3
00000044 mov ecx,60854186h
00000049 call FFF5FD70
0000004e mov dword ptr [ebp-4Ch],eax
00000051 lea ecx,[ebp-50h]
00000054 mov edx,872618h
00000059 call 61490806
0000005e lea eax,[ebp-50h]
00000061 push dword ptr [eax]
00000063 mov ecx,dword ptr [ebp-4Ch]
00000066 call 614908E3
0000006b mov ecx,dword ptr [ebp-4Ch]
0000006e call dword ptr ds:[008726D8h]
00000074 mov dword ptr [ebp-54h],eax
00000077 mov eax,dword ptr [ebp-54h]
0000007a mov dword ptr [ebp-40h],eax
var ints = new List<int> { 1, 2, 3 };
0000007d mov ecx,60B59894h
00000082 call FFF5FBE0
00000087 mov dword ptr [ebp-58h],eax
0000008a mov ecx,dword ptr [ebp-58h]
0000008d call 60805DB0
00000092 mov eax,dword ptr [ebp-58h]
00000095 mov dword ptr [ebp-48h],eax
00000098 mov ecx,dword ptr [ebp-48h]
0000009b mov edx,1
000000a0 cmp dword ptr [ecx],ecx
000000a2 call 608070C0
000000a7 nop
000000a8 mov ecx,dword ptr [ebp-48h]
000000ab mov edx,2
000000b0 cmp dword ptr [ecx],ecx
000000b2 call 608070C0
000000b7 nop
000000b8 mov ecx,dword ptr [ebp-48h]
000000bb mov edx,3
000000c0 cmp dword ptr [ecx],ecx
000000c2 call 608070C0
000000c7 nop
000000c8 mov eax,dword ptr [ebp-48h]
000000cb mov dword ptr [ebp-44h],eax
}
答案 3 :(得分:6)
我想在第一种情况下,元素会自动添加到列表中,而在第二种情况下,首先创建一个数组,然后迭代它,并将每个元素添加到列表中。
虽然可能会优化第二个以避免真正的阵列创建,但值得注意的是,如果此操作在循环内完成,则可能是对象分配量的两倍(除非它是直接优化的)没有必要这样做。
你应该检查字节码以确定它。
我不喜欢C#内部,但请小心谨慎!
答案 4 :(得分:1)
我喜欢第一个版本。但是关于性能,我认为最好是使用数组并明确定义元素的数量,如果这当然是可能的:
var x = new int[3] { 1, 3, 3 }.ToList();