简体   繁体   中英

new [] or new List<T>?

I'm just thinking about the styling and performance. Previously I used to write something like,

var strings = new List<string> { "a", "b", "c" };
var ints = new List<int> { 1, 2, 3};

But now I tend to like this style more,

var strings = new [] { "a", "b", "c" }.ToList();
var ints = new [] { 1, 2, 3}.ToList();

I prefer the second style, but now considering - is it really worth to write it like that or maybe it's not that efficient and requires more operations?

I disagree with Darin: they're not equivalent in terms of performance. The latter version has to create a new array, and ToList will then copy it into the new list. The collection initializer version is equivalent to:

var tmp = new List<int>();
tmp.Add(1);
tmp.Add(2);
tmp.Add(3);
var ints = tmp;

Assuming the list starts off with a large enough buffer, that won't require any further allocation - although it will involve a few method calls. If you do this for a very large number of items, then it will require more allocations than the ToList version, because it will copy the items as it goes.

The performance difference is likely to be negligible, but it's non-zero (and not clearly better in either direction - there are fewer calls in the array version, but more allocation).

I would concentrate more on style than performance unless you have a reason to suspect that the difference is significant, in which case you should measure rather than just guessing.

Personally I prefer the first form - I think it makes it clearer that you're using a list right from the start. Another alternative would be to write your own static class:

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

Then you can write:

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

This still makes it clear that you're using lists, but takes advantage of type inference.

You may well consider it overkill though :)

Setting aside the difference between the two from a performance perspective, the former expresses what you are trying to achieve in a better way.

Consider expressing the code in English:

declare a list of strings with these contents

And

declare an array of strings with these contents and then convert it into a list of strings

To me, the first seems more natural. Although I acknowledge the second may be better for you.

Example 1 (var ints = new List { 1, 2, 3};): Provides a 31.5% overhead (Eumerable.ToList) and List.Add() causes a 8.7% overhead.

Where as example 2: Causes a 11.8% overhead on List.ctor and a 5% for Ensure Capacity.

(Results from Red Gate ANTS Performance Profiler)

You can see that var ints = new List { 1, 2, 3}; has more operations to perform via the disassembly

 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 
        }

I guess in the first case elements are automatically added to the list while in the second one first an array is created then it is iterated and every element is added to the list.

While probably second one will be optimized to avoid a real array creation it is worth noticing that if this operation is done inside a loop you probably twice the object allocation amount (unless it's straightly optimized) with no real need to do that.

You should check bytecode to be sure of it.

I'm not fond of C# internals though so take this with care!

I like the first versions. But regarding perfomance I think the best is to use the array and define specifically the number of elements is going to be if of course this can be possible:

var x = new int[3] { 1, 3, 3 }.ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM