Подтвердить что ты не робот

Новый [] или новый список <T>?

Я просто думаю о стилизации и исполнении. Раньше я писал что-то вроде

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

Я предпочитаю второй стиль, но теперь рассматриваю - действительно ли стоит писать его так, или, может быть, это не так эффективно и требует больше операций?

4b9b3361

Ответ 1

Я не согласен с Дарином: они не эквивалентны с точки зрения производительности. Последняя версия должна создать новый массив, а 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

Это все еще дает понять, что вы используете списки, но использует вывод типа.

Вы можете счесть это излишним:)

Ответ 2

Отбросив разницу между двумя с точки зрения производительности, первая выражает то, чего вы пытаетесь достичь в лучшем виде.

Рассмотрим выражение кода на английском языке:

объявить список строк с этим содержимым

и

объявить массив строк с этим содержимым, а затем преобразовать его в список строк

Для меня первое кажется более естественным. Хотя я признаю, что второй может быть лучше для вас.

Ответ 3

Пример 1 (var ints = new List {1, 2, 3};): Предоставляет накладные расходы на 31,5% (Eumerable.ToList) и List.Add() вызывает 8,7% накладных расходов.

Где в качестве примера 2: Вызывает 11,8% накладных расходов на List.ctor и 5% для обеспечения емкости.

(результаты из профилировщика профилей Red Gate ANTS)

Вы можете видеть, что 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 
        }

Ответ 4

Я предполагаю, что в первом случае элементы автоматически добавляются в список, а во втором - сначала создается массив, после чего он повторяется и каждый элемент добавляется в список.

Хотя, вероятно, второй будет оптимизирован, чтобы избежать создания реального массива, стоит заметить, что если эта операция выполняется внутри цикла , вы, вероятно, в два раза превышаете объем размещения объекта (если только он не будет оптимизирован) не нужно это делать.

Вы должны проверить байт-код, чтобы убедиться в этом.

Я не люблю внутренние элементы С#, хотя и берем это с осторожностью!

Ответ 5

Мне нравятся первые версии. Но в отношении производительности я считаю, что лучше всего использовать массив и определить, в частности, количество элементов будет, если, конечно, это возможно:

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