2013-06-24 4 views
2

Я хочу, чтобы преобразоватьЯвляются ли эти две инициализации списка идентичными?

var aList = new List<string>(new string[] { "elem1", "elem2", "elem3" });

инициализаций в

var aList = new List<string>() { "elem1", "elem2", "elem3" };

в нашем исходном коде. Я считаю, что у последнего нет ненужного создания массива и массива -> Преобразование списка. Или первый тоже? Или компилятор все равно оптимизирует его? Могу ли я столкнуться с нежелательными побочными эффектами (или отсутствием побочных эффектов) позже?

Проект использует .NET 4.

+0

компилятор не будет оптимизировать его, поскольку он реализовал функциональность List (у него есть конструктор с параметром IEnumerable). Поэтому он будет преобразован, и ничего плохого не произойдет. –

+0

[http://www.dotnetperls.com/initialize-list](http://www.dotnetperls.com/initialize-list) говорит интересные вещи. Моя вторая вариация компилируется в ту, что говорит Шломо (Add calls). Вариант массива может быть более оптимальным: «копирует внешний массив во внутренний буфер списка во время выполнения, что позволяет избежать ненужного изменения размера буфера списка». –

+0

Итак, нет никакого ненужного создания массива, как я утверждаю в своем вопросе. –

ответ

4

Они не совсем эквивалентны.

  1. В первом случае вы создаете новый массив, то мимоходом, что в List<T> конструктор, который будет создавать свой собственный внутренний массив того же размера и ссылаться на CopyTo метод массива источников, чтобы скопировать элементы из исходный массив и его внутренний массив.

  2. Во втором случае вы строите новый List<T> с первоначально пустым массивом (размера _defaultCapacity = 4), а затем, вызывая Add метода, Лист, который может вызвать внутренний массив будет изменен несколько раз, как это добавление элементов.

Таким образом, в первом случае, Вы получаете выгоду от не имея размер внутреннего массива в списке, так же как вызов потенциально более эффективный CopyTo метод, а не итеративного Add, за счет того, чтобы создать два массивы в памяти сразу.

Вот одна вещь, которую вы могли бы сделать, чтобы избежать создания двух массивов и убедитесь, что вы не должны изменять размер внутреннего массива в Листом:

var aList = new List<string>(3) { "elem1", "elem2", "elem3" }; 

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

+0

[http://www.dotnetperls.com/initialize-list](http://www.dotnetperls.com/initialize-list) говорит то же самое. Учитывая, что у меня нет ничего прекрасного, поэтому на самом деле есть только строковые литералы как элементы, версия массива может быть более оптимальной, хотя крошечный бит дольше. Интересно. –

+2

Обратите внимание, что для числа элементов это малое, разница в производительности вряд ли имеет значение (ощутимо). Наивысшее значение имеет правильность и читаемость. Они все правильные, поэтому они просто сводятся к удобочитаемости/ремонтопригодности. Если списки достаточно велики, что производительность действительно имеет значение, вы почти наверняка не должны определять их в коде; данные должны существовать в файле/базе данных или что-то в этом роде. – Servy

+0

@CsabaToth У меня не было никаких реальных тестов, но я бы предположил, что у вас будет значительно улучшенная производительность по времени с помощью первого метода, если ваш массив большой (учитывая, что стоимость изменения размера и метод CopyTo, вероятно, более эффективны) - но опять же стоимость с точки зрения памяти также больше. –

1

Последний компилируется в:

aList = new List<string(); 
aList.Add("elem1"); 
aList.Add("elem2"); 
aList.Add("elem3"); 

Конструктор выглядит, как он делает что-то похожее на это (с некоторой обработкой ошибок):

foreach(var t in items) 
    Add(t); 

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

+0

Интересно, я это рассмотрю. –

+0

Возможно, я должен был задать свой вопрос таким образом: какая инициализация более оптимальна с точки зрения времени выполнения. –

1

Если конвертируется код будет как следующий:

var aList = new List<string>(3 /* !capacity specified */) { "elem1", "elem2", "elem3" }; 

Он не имеет «создание ненужного массива» (в случае, когда вы задаете более Список <> :: _ defaultCapacity элементы).

С трех (или четырех) строки, которые вы код также не имеет «ненужное создание массива», потому что _defaultCapacity == 4.

Другими словами, во втором коде (с коллекции инициализаторе без указания мощности) внутренний список <> `s массив можно воссоздать несколько раз.

+0

Да, оказывается, что нет ненужного создания массива. Вероятно, эта версия еще более оптимальна. –

Смежные вопросы