.NET 6: Улучшения коллекций. Окончание
3. Улучшения сериализации для словарей
В то время как сериализация списочных коллекций довольно проста, коллекции, для которых требуется компонент хеширования, такие как
Dictionary и HashSet, создают дополнительные проблемы. Одна из таких проблем - необходимость сериализации не только содержимого, но и используемого алгоритма сравнения. Чтобы десериализатор знал, должен ли он создавать коллекцию с порядковым компаратором, зависящим от языка и региональных параметров и чувствительным или нечувствительным к регистру.Поскольку подавляющее большинство этих проблем связано со строковыми ключами, было решено добавить два новых метода в
StringComparer:public static bool IsWellKnownOrdinalComparer(Проверяя результат этих функций, сериализатор может собрать необходимую информацию для последующей десериализации. Хотя методы не охватывают всех сценариев, редко можно встретить настолько специализарованный компаратор, не основанный на известной культуре.
IEqualityComparer<string?>? comparer,
out bool ignoreCase);
public static bool IsWellKnownCultureAwareComparer(
IEqualityComparer<string?>? comparer,
[NotNullWhen(true)] out CompareInfo? compareInfo,
out CompareOptions compareOptions);
Однако это не полное решение. Поскольку ни XML, ни JSON не позволяют связывать свойства с коллекциями, сериализаторам всё равно нужно будет определять собственный способ хранения информации.
4. Очередь с приоритетом
Новый класс
PriorityQueue разработан для сценариев, когда разработчику нужна очередь, в которой элементы помещаются в список на основе значения приоритета. Это можно реализовать несколькими способами, многие из которых зависят от вопроса: «Можно ли изменять приоритет элемента?».Для
PriorityQueue было решено не допускать изменения приоритета. Создатели определили, что фиксированное значение приоритета приведёт к 2-3-кратному улучшению производительности.Чтобы гарантировать, что приоритет не может быть изменён, он хранится в очереди отдельно от объекта:
public void Enqueue(TElement element, TPriority priority);Следующий вопрос - стабильность. Если вы добавляете в очередь два элемента с одинаковым приоритетом, и они гарантированно извлекаются из очереди в том же порядке, то очередь считается стабильной. В .NET решили не предоставлять стабильную очередь, опять же во имя быстродействия.
Ещё вопрос: разрешить ли перечисление очереди. На первый взгляд он может показаться странным. Почему бы не использовать
foreach для очереди?Первая проблема - это подразумеваемый контракт для
IEnumerable. Большинство разработчиков предполагают, что вы можете дважды перечислить одну и ту же коллекцию и оба раза получить одинаковый результат. Это предположение встроено в общие шаблоны, где не всегда очевидно, что перечисление вообще происходит. Например, вызов метода Count() может перечислить элементы, что приведёт к опустошению очереди. Что означает, что вызванный после этого foreach увидит пустую очередь.Можно сделать перечислитель неразрушающим, но в этом есть свои проблемы. Внутренне приоритетная очередь не обязательно упорядочена. Это означает, что перечислитель должен будет отслеживать, какие элементы он уже видел. Если по какой-то причине вам понадобится запустить несколько перечислений одновременно, каждый, по идее должен был бы получить полную копию очереди.
Таким образом, было решено, что класс
PriorityQueue не будет реализовывать IEnumerable<T>. Это, в свою очередь, означает, что он также не может реализовать ICollection<T> или другие подобные интерфейсы.Если вы действительно хотите использовать
PriorityQueue в foreach, можно добавить метод расширения:public static IEnumerable<TElement>Источник: https://www.infoq.com/news/2021/06/Net6-Collections/
GetDequeuingEnumerator<TElement, TPriority>(
this PriorityQueue<TElement, TPriority> queue)
{
while (queue.TryDequeue(out var item))
yield return item;
}