Используем Выражения Коллекций для Пользовательских Типов
В C#12 появились выражения коллекций — новый упрощённый синтаксис для инициализации коллекций:
int[] numbers = [1, 2, 3, 4, 5];
List<string> names = ["Alice", "Bob", "Charlie"];
Этот синтаксис отлично работает со встроенными типами коллекций, но как насчёт наших типов коллекций? Здесь на помощь приходит атрибут CollectionBuilderAttribute, позволяющий расширить этот современный синтаксис на пользовательские типы.
Пользовательские коллекции
Представьте, что вы создали свой тип коллекции:
public class MyCollection<T>
{
private readonly List<T> _items;
public MyCollection(ReadOnlySpan<T> items) =>
_items = [.. items];
public IEnumerator<T> GetEnumerator()
=> _items.GetEnumerator();
// другие члены…
}
Раньше вы не могли использовать синтаксис выражений коллекций для этого типа. Вам приходилось использовать старый способ:
var myCol =
new MyCollection<int>(new[] { 1, 2, 3, 4, 5 });
Либо (что не сильно меняет дело):
var myCol =
new MyCollection<int>([1, 2, 3, 4, 5]);
Не слишком элегантно.
Атрибут CollectionBuilderAttribute устраняет этот разрыв, сообщая компилятору, как конструировать вашу коллекцию из выражения коллекции:
[CollectionBuilder(typeof(MyCollectionBuilder),
nameof(MyCollectionBuilder.Create))]
public class MyCollection<T>
{
//…
}
public static class MyCollectionBuilder
{
public static MyCollection<T>
Create<T>(ReadOnlySpan<T> items)
=> new([..items]);
}
Теперь мы можем использовать:
MyCollection<int> myCol = [1, 2, 3, 4, 5];
Компилятор автоматически вызовет метод Create, передав ему элементы.
Как это работает
Атрибут принимает два параметра:
1. Тип построителя – тип, содержащий фабричный метод (
typeof(MyCollectionBuilder));2. Имя метода – имя статического метода, создающего экземпляр (
"Create").Метод построителя должен:
- быть статическим;
- принимать либо ReadOnlySpan<T> (предпочтительно), либо T[];
- возвращать экземпляр типа коллекции;
- иметь параметры типа, соответствующие вашей коллекции.
Замечание: также необходимо, чтобы коллекция имела «тип итерации», то есть имела метод
GetEnumerator(), возвращающий IEnumerator (или IEnumerator<T>). Можно либо реализовать интерфейс IEnumerable или IEnumerable<T>, либо просто добавить метод GetEnumerator().Когда всё это реализовано, компилятор может сгенерировать необходимый код для построения вашей коллекции наиболее эффективным способом.
Источник: https://bartwullems.blogspot.com/2025/11/how-to-uninstall-older-net-core-versions.html