TGViewer
C# Heppard C# Heppard @csharp_gepard · 1.65K subscribers
Post #121 2.43K
TryGetNonEnumerated #память

Хотелось бы напомнить про такую банальную, но весьма полезную оптимизацию, как создание списка с заранее известным размером.

Напомню, что первоначально List<T> создаётся с внутренним массивом размера 0. При последующем добавлении элементов происходит проверка, и, если места не хватает, внутренний массив расширяется на свой размер, умноженный на 2. «Расширение», в данном случае, означает, что создаётся новый массив, а содержимое старого массива копируется в новый. Таким образом, если мы заранее создадим List с внутренним массивом в 200 элементов, то мы избежим аллокаций шести массивов - это весьма солидно .

Однако, увы, некоторые методы возвращают IEnumerable<T>, из которого весьма проблематично узнать размер. Да, за IEnumerable<T> может скрываться любая из коллекций, имплементирующая ICollection<T>, и тогда проблем с выяснением первоначального размера нашей коллекции нет. Но что если нам пришёл результат чего-то вот такого?


_data = array // первоначальный массив
.Skip(1)
.Take(Count / 2)
.Order()
.Select(static i => i * i % 10 == 0 ? "да" : "нет");


Это точно не ICollection<string>, то есть выяснить размер мы не сможем. Вернее, всё-таки сможем. Если заглянуть в недра .NET, то мы узнаем, что это некий Enumerable.SelectIPartitionIterator, который, на наше счастье, реализует внутренний интерфейс IIListProvider. Чтобы попытаться воспользоваться его методом GetCount, нам поможет метод TryGetNonEnumeratedCount, который появился аж в .NET 6.

В нашем случае он может быть применён вот так:


var capacity = _data.TryGetNonEnumeratedCount(out var count)
? count
: ваша_эвристическая_константа;

var list = new List<string>(capacity);
list.AddRange(_data);


Почему этот подход не используется в конструкторе того-же List’a (который принимает IEnumerable) и в его же методе AddRange - загадка. Наверное, у коллег пока просто не дошли руки.

P.S.: Для желающих посмотреть, что метод TryGetNonEnumerated действительно ничего не перебирает, а просто возвращает значение - в комментариях есть бенчмарк.
  • 👍 24
  • ❤ 5
More from @csharp_gepard
  1. Mar 13, 2026Ozon Tech Community .NET Meetup 24 марта, лофт Casa Picassa, 19:00 Ищем способы бороться с…
  2. Jan 20, 2026Ещё одна история про память #отдых Судя по комментариям специалистов и ценам на RAM в мага…
  3. Nov 25, 2025FastEnum #скорость Иногда нам нужно не просто быстро, а очень быстро. В этот момент в дело…
  4. Nov 20, 2025UnsafeAccessor #скорость Иногда возникает странное желание изменять приватные поля в класс…
  5. Nov 17, 2025Latency numbers every programmer should know Я всё время теряю эти циферки, особенно когда…
  6. Oct 29, 2025Dictionary.TryGetValue #скорость Уж сколько лет прошло и, вроде, все это знают. Но, тем не…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →