.NET 6: Улучшения коллекций. Начало
1. Ёмкость списка, стека и очереди
Перед добавлением большого количества элементов в
Dictionary или HashSet полезно вызвать EnsureCapacity с ожидаемым размером коллекции. Это позволяет коллекции выполнить одну операцию изменения размера заранее, избегая необходимости делать это несколько раз. Метод EnsureCapacity был добавлен в классы List<T>, Stack<T> и Queue<T>, также для повышения производительности.Заметным исключением из этой группы является
Collection<T>. В отличие от других коллекций, Collection<T> может при желании обернуть другую коллекцию, которая не обязательно предоставляет метод EnsureCapacity. Её потомок, ObservableCollection<T>, также не может предоставить метод EnsureCapacity.Это не единственный недостаток
Collection<T> и ObservableCollection<T>. Отсутствие метода AddRange давно раздражало разработчиков. А также им не хватает высокопроизводительного IEnumerator на основе структур, который предлагает List<T>.2. Изменяемые структуры и словари
Хотя и редко, разработчикам иногда приходится работать с изменяемыми структурами. Это может вызывать трудности, потому что легко случайно скопировать изменяемую структуру, в результате чего два значения больше не будут синхронизироваться.
Чтобы решить эту проблему, приходилось намеренно копировать структуру, вносить изменения, а затем копировать её обратно в исходное место. Для небольших конструкций это неплохо, но для больших может быть дорого. А так как производительность – чаще всего первопричина использования изменяемых структур, использование этого метода контрпродуктивно.
Чтобы избежать этих ненужных копий, изменяемые структуры обычно хранились в массивах. В отличие от свойства-индексатора в
List<T>, доступ к элементам массива осуществляется напрямую.В C# 7 были введены ссылочные возвращаемые значения (ref return). Это позволило индексаторам возвращать ссылку на объект, а не копию.
public ref int this[int index] {
get { return ref _internalArray[index]; }
}
Этот метод используется структурой Span<T>, начиная с .NET Core 2.1. Начиная с .NET 5, метод CollectionsMarshal.AsSpan позволяет легко получить span-обёртку коллекции.Чтобы предложить те же возможности для словарей, была создана новая функция под названием
CollectionsMarshal.GetValueRefOrNullRef. Есть несколько интересных фактов об этой функции:1. Это не метод расширения. Разработчики опасались, что его будет слишком легко использовать неправильно, поэтому они намеренно сделали так, чтобы его было сложно найти. (Функцию
AsSpan также потенциально небезопасно использовать, поскольку размеры коллекции не могут быть изменены, пока существует Span<T>.)2. Существует внутренний метод
Dictionary<TKey, TValue>.FindValue. Он и используется в GetValueRefOrNullRef:public static ref TValueFindValue сам по себе использует некоторые методы, которые не распространены в программировании на C#, вроде
GetValueRefOrNullRef<TKey, TValue>
(Dictionary<TKey, TValue> dictionary, TKey key)
where TKey : notnull
=> ref dictionary.FindValue(key);
goto, включая обратные переходы.3. После вызова
GetValueRefOrNullRef нужно использовать CompilerServices.Unsafe.IsNullRef, чтобы проверить, является ли результат ссылкой на фактическое значение или на null. Это связано с тем, что в C# нет синтаксиса для проверки того, является ли ссылка на структуру нулевой.Окончание следует…
Источник: https://www.infoq.com/news/2021/06/Net6-Collections/