2015-07-11 2 views
4

Мне просто интересно, что происходит при звонке .ToList() на IEnumerable в C#. Действительно ли элементы копируются в полностью новые дублированные элементы в куче или новый список просто ссылается на оригинальные элементы в куче?Влияние IEnumerable.ToList()

Мне интересно, потому что кто-то сказал мне, что это дорого назвать ToList, тогда как если просто назначить существующие объекты новому списку, это легкий вызов.

Я написал эту скрипку https://dotnetfiddle.net/s7xIc2 Просто проверяет хэш-код достаточно, чтобы знать?

+0

Конечно, есть сценарии, где будут проблемы. Меня больше интересует механика того, производится ли копия предметов. Соображения относительно размера списка - это еще одно обсуждение. –

+1

Большинство .Net-кода общедоступны - поэтому http://referencesource.microsoft.com должно быть ваше первое место, чтобы проверить, какой именно звонок ... И чем просить разъяснения по частям вы не понимаете. –

+1

'.ToArray()' немного дешевле с точки зрения памяти. Он усекает перед возвращением. '.ToList()' поддерживает буфер мощности, который часто превышает длину фактического списка. – Enigmativity

ответ

7

IEnumerable не должен содержать список чего-либо. Он может (и часто делает) разрешать каждый текущий пункт в момент его запроса.

С другой стороны, IList - это полная копия всех предметов в памяти.

Итак, ответ ... Это зависит. Что поддерживает IEnumerable? Если его файловая система тогда да, вызов .ToList может быть довольно дорогим. Если его список в памяти уже, то нет, вызов .ToList не будет ужасно дорогим.

В качестве примера предположим, что вы создали IEnumerable, который генерировал и возвращал случайное число каждый раз .Next вызывался. В этом случае вызов .ToList в IEnumerable никогда не вернется и в конечном итоге вызовет исключение Out Of Memory.

Однако IEnumerable объектов базы данных имеет конечные границы (обычно :)), и пока все данные вписываются в память, вызов .ToList может быть полностью уместным.

+0

В этом конкретном сценарии данные являются объектами POCO из запроса Entity Framework –

+1

Вызов .ToList на IQueryable считается лучшей практикой. –

+0

Спасибо за ответы. Это немного задержало меня, когда обсуждалось обсуждение, потому что я был уверен, что до тех пор, пока элементы будут ссылочными, тогда будут сделаны только «ссылки». Просто спрашивая парня с монументальным количеством опыта больше, чем я, у меня было второе предположение. –

3

Вот одна версия ToList:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) 
{ 
    if (source == null) throw Error.ArgumentNull("source"); 
    return new List<TSource>(source); 
} 

Это создает новый список из источника, вот конструктор:

// Constructs a List, copying the contents of the given collection. The 
// size and capacity of the new list will both be equal to the size of the 
// given collection. 
// 
public List(IEnumerable<T> collection) { 
    if (collection==null) 
     ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection); 
    Contract.EndContractBlock(); 

    ICollection<T> c = collection as ICollection<T>; 
    if(c != null) { 
     int count = c.Count; 
     if (count == 0) 
     { 
      _items = _emptyArray; 
     } 
     else { 
      _items = new T[count]; 
      c.CopyTo(_items, 0); 
      _size = count; 
     } 
    }  
    else {     
     _size = 0; 
     _items = _emptyArray; 
     // This enumerable could be empty. Let Add allocate a new array, if needed. 
     // Note it will also go to _defaultCapacity first, not 1, then 2, etc. 

     using(IEnumerator<T> en = collection.GetEnumerator()) { 
      while(en.MoveNext()) { 
       Add(en.Current);          
      } 
     } 
    } 
} 

Она копирует предметы.

Код здесь: referencesource.microsoft.com

+0

Я не понимаю голоса. Я не написал код! –

+0

Не мой нисходящий знак по атрибуции кода * очень * неясен. –

+0

Steve Wellens - Случается постоянно на этом сайте. Постарайтесь помочь, и люди становятся настолько придирчивыми, как будто они меняют ситуацию. Поэтому, учитывая, что я задал вопрос в первую очередь, я скажу, что этот код очень полезен, и я очень благодарю вас. Он служил двум целям - я вижу, что он делает, и теперь я знаю, что MS выпустила код для публики, о котором я не знал. Этот ответ был полезен. Это код рамки, так что ясно или нет, это не касается каких-либо комментаторов. –

1

ToList() создать новый объект списка, который содержит ссылки на исходные объекты или копию объекта, если они struct.

Например, список int будет иметь полную копию. Список «Продукт» будет относиться только к продукту, а не к полной копии. Если оригинал изменен, продукт в списке также будет изменен.

+1

Нет, это не так. Вы можете попробовать его и увидеть «Список L1 = новый Список (); L1.Add (1); L1.Add (1); L1.Add (1); Список L2 = L1.ToList(); L2 [1] = 4; 'После изменения L2 L1 остается неизменным. –

+0

@SteveWellens, я думаю, что Zyo правильно говорит, что список экземпляров объектов «продукта» будет ссылочными копиями этих объектов и будет вести себя по его словам. Ваш примерный комментарий использует целые числа, которые являются типами значений и, следовательно, будут полными копиями, аналогичными, если бы они были структурами. – BateTech

+0

@SteveWellens. Вы, к примеру, верны, так же как и мое объяснение. int - [тип значения] (https://msdn.microsoft.com/en-us/library/s1ax56ch.aspx), как и структура, и всегда копируется, поэтому оригинал не обновляется. – Zyo

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