new []或new List <t>?</t>

时间:2012-03-30 12:20:56

标签: c# .net performance

我只想到造型和性能。以前我曾经写过类似的东西,

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();

我更喜欢第二种风格,但现在正在考虑 - 是否真的值得这样写,或者它不是那么有效并且需要更多操作?

5 个答案:

答案 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();