Новый [] или новый список <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();
Я предпочитаю второй стиль, но теперь рассматриваю - действительно ли стоит писать его так, или, может быть, это не так эффективно и требует больше операций?
Ответы
Ответ 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();