Аргументы в Выражениях Коллекций в C#15
В C#15 реализовано точечное улучшение выражений создания коллекций: возможность передавать аргументы с помощью элемента `with(…)`, указываемого в начале выражения.
Если вы уже используете выражения создания коллекций из C#12, это нововведение устраняет распространённое неудобство: теперь можно передавать аргументы (характерные для конструкторов или фабричных методов) непосредственно внутри
[…].Сравнение C# версий 12, 13 и 15
C#12 - Добавлены выражения создания коллекций (
[…]) и spread-оператор (..):int[] values = [1, 2, 3];
int[] all = [0, ..values, 4];
C#13 - Расширена поддержка
params для разных типов коллекций (не только массивов) в параметрах методов:csharp
public void LogValues(params Span<int> numbers)
{
// …
}
LogValues(1, 2, 3);
C#15 - Добавлен элемент
with(…) в начало выражений создания коллекцийList<int> numbers =
[with(capacity: 100), 1, 2, 3, ..more];
with(…) предоставляет аргументы для создания коллекции, где это поддерживается (параметры конструктора, построитель Create(…), отдельные сигнатуры интерфейсов).При этом
with(…) должен быть первым элементом.Практические примеры
1) Предварительное определение размера коллекций для обеспечения читаемости и ясности намерений
List<int> ids = [with(capacity: 256), ..sourceIds];
Это позволяет выполнить инициализацию в рамках одного выражения и делает ваш замысел очевидным.
2) Сценарии использования построителей коллекций
Для построителей коллекций C#15 поддерживает дополнительные параметры метода
Create(…):static MyCollection<T>
Create(SomeOption option, ReadOnlySpan<T> items)
{
// …
}
Использование:
Tags tags = [with(StringComparer.OrdinalIgnoreCase), "CSharp", "CSHARP", "csharp", "dotnet"];
Tags newTags = [with(), "CSharp", "CSHARP", "csharp", "dotnet"];
Tags oldTags = ["CSharp", "CSHARP", "csharp", "dotnet"];
[CollectionBuilder(typeof(Tags), nameof(Create))]
internal sealed class Tags(
string[] values,
StringComparer comparer)
: HashSet<string>(values, comparer)
{
public static Tags Create(
StringComparer comparer,
ReadOnlySpan<string> items)
=> new([.. items], comparer);
public static Tags Create(ReadOnlySpan<string> items)
=> new([.. items], StringComparer.OrdinalIgnoreCase);
}
Ограничения и нюансы
1. Если целевым типом является массив или span, использование
with(…) невозможно.2. Аргументы внутри
with(…) не могут иметь тип dynamic.3. Согласно замыслу, аргументы
with(…) игнорируются при принятии решений о преобразовании или выводе типов (по аналогии с new(…)).4. Действуют обычные правила выбора перегрузки конструктора или построителя. Если подходят несколько вариантов, возможна неоднозначность.
Почему важны аргументы выражений коллекций в C#15
C#15 улучшает инициализацию коллекций в одно выражение, обеспечивая:
- Более ясное выражение намерений (указание вместимости, опций, компараторов и т.д., где это поддерживается);
- Сокращение числа отдельных инструкций инициализации;
- Более чистый API для пользовательских построителей коллекций.
Источник: https://laurentkempe.com/2026/09/26/csharp-15-collection-expression-arguments/