From 71f695c30e903eab58d94d44bd3c9da72a3a9561 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 3 Feb 2026 16:45:41 -0500 Subject: [PATCH 01/12] Skeletons for C# 15 what's new Build the initial framework for What's new in C# 15. --- .openpublishing.redirection.csharp.json | 4 +-- docfx.json | 6 +++- .../includes/default-langversion-table.md | 1 + .../includes/langversion-table.md | 1 + .../language-reference/language-versioning.md | 2 +- docs/csharp/toc.yml | 6 ++++ docs/csharp/whats-new/csharp-15.md | 32 +++++++++++++++++++ 7 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 docs/csharp/whats-new/csharp-15.md diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index 4706854645830..0092422dc85fe 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -5014,7 +5014,7 @@ }, { "source_path_from_root": "/docs/csharp/whats-new.md", - "redirect_url": "/dotnet/csharp/whats-new/csharp-14", + "redirect_url": "/dotnet/csharp/whats-new/csharp-15", "redirect_document_id": true }, { @@ -5055,7 +5055,7 @@ }, { "source_path_from_root": "/docs/csharp/whats-new/index.md", - "redirect_url": "/dotnet/csharp/whats-new/csharp-14", + "redirect_url": "/dotnet/csharp/whats-new/csharp-15", "ms.custom": "updateeachrelease" }, { diff --git a/docfx.json b/docfx.json index 32baf4eabedc3..472779e1a4754 100644 --- a/docfx.json +++ b/docfx.json @@ -74,6 +74,7 @@ "Compiler Breaking Changes - DotNet 8.md", "Compiler Breaking Changes - DotNet 9.md", "Compiler Breaking Changes - DotNet 10.md", + "Compiler Breaking Changes - DotNet 11 .md", "Deviations from Standard.md" ], "src": "_roslyn/docs/compilers/CSharp", @@ -517,7 +518,8 @@ "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "11/08/2022", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "11/08/2023", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "11/09/2024", - "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md": "01/09/2024", + "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md": "11/09/2024", + "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 11.md": "01/09/2025", "_roslyn/docs/compilers/CSharp/Deviations from Standard.md": "04/24/2025", "_vblang/spec/*.md": "07/21/2017" }, @@ -697,6 +699,7 @@ "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md": "C# compiler breaking changes since C# 13", + "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 11.md": "C# compiler breaking changes since C# 14", "_roslyn/docs/compilers/CSharp/Deviations from Standard.md": "Deviations from the C# standard", "_vblang/spec/introduction.md": "Introduction", "_vblang/spec/lexical-grammar.md": "Lexical grammar", @@ -823,6 +826,7 @@ "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "Learn about any breaking changes since the initial release of C# 11 and included in C# 12", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "Learn about any breaking changes since the initial release of C# 12 and included in C# 13", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md": "Learn about any breaking changes since the initial release of C# 13 and included in C# 14", + "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 11.md": "Learn about any breaking changes since the initial release of C# 14 and included in C# 15", "_roslyn/docs/compilers/CSharp/Deviations from Standard.md": "Learn about any deviations from the C# standard", "_vblang/spec/introduction.md": "This chapter provides an overview of the Visual Basic language and its design goals.", "_vblang/spec/lexical-grammar.md": "This chapter defines the lexical grammar for Visual Basic.", diff --git a/docs/csharp/language-reference/includes/default-langversion-table.md b/docs/csharp/language-reference/includes/default-langversion-table.md index f9185ba55aa01..268b9da577954 100644 --- a/docs/csharp/language-reference/includes/default-langversion-table.md +++ b/docs/csharp/language-reference/includes/default-langversion-table.md @@ -4,6 +4,7 @@ ms.custom: "updateeachrelease" | Target | Version | C# language version default | |------------------|---------|-----------------------------| +| .NET | 11.x | C# 15 | | .NET | 10.x | C# 14 | | .NET | 9.x | C# 13 | | .NET | 8.x | C# 12 | diff --git a/docs/csharp/language-reference/includes/langversion-table.md b/docs/csharp/language-reference/includes/langversion-table.md index d7d81b3b80f23..946050c676652 100644 --- a/docs/csharp/language-reference/includes/langversion-table.md +++ b/docs/csharp/language-reference/includes/langversion-table.md @@ -7,6 +7,7 @@ ms.custom: "updateeachrelease" | `preview` | The compiler accepts all valid language syntax from the latest preview version. | | `latest` | The compiler accepts syntax from the latest released version of the compiler (including minor version). | | `latestMajor`
or `default` | The compiler accepts syntax from the latest released major version of the compiler. | +| `15.0` | The compiler accepts only syntax that is included in C# 15 or lower. | | `14.0` | The compiler accepts only syntax that is included in C# 14 or lower. | | `13.0` | The compiler accepts only syntax that is included in C# 13 or lower. | | `12.0` | The compiler accepts only syntax that is included in C# 12 or lower. | diff --git a/docs/csharp/language-reference/language-versioning.md b/docs/csharp/language-reference/language-versioning.md index ab9665c33cb40..858014485e1f9 100644 --- a/docs/csharp/language-reference/language-versioning.md +++ b/docs/csharp/language-reference/language-versioning.md @@ -11,7 +11,7 @@ The latest C# compiler determines a default language version based on your proje [!INCLUDE[csharp-version-note](./includes/initial-version.md)] -[C# 14](../whats-new/csharp-14.md) is supported only on .NET 10 and newer versions. [C# 13](../whats-new/csharp-13.md) is supported only on .NET 9 and newer versions. [C# 12](../whats-new/csharp-12.md) is supported only on .NET 8 and newer versions. Using a C# language version newer than the version associated with your target TFM is unsupported. +[C# 15](../whats-new/csharp-15.md) is supported only on .NET 11 and newer versions. [C# 14](../whats-new/csharp-14.md) is supported only on .NET 10 and newer versions. [C# 13](../whats-new/csharp-12.md) is supported only on .NET 9 and newer versions. Using a C# language version newer than the version associated with your target TFM is unsupported. For details on which .NET versions are supported by versions of Visual Studio, see the [Visual Studio platform compatibility](/visualstudio/releases/2026/compatibility#-visual-studio-support-for-net-development) page. diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index 5324dd7a241eb..feb328293414b 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -142,6 +142,10 @@ items: href: fundamentals/exceptions/how-to-execute-cleanup-code-using-finally.md - name: What's new in C# items: + - name: C# 15 + items: + - name: What's new in C# 15 + href: whats-new/csharp-15.md - name: C# 14 items: - name: What's new in C# 14 @@ -156,6 +160,8 @@ items: href: whats-new/csharp-12.md - name: Breaking changes items: + - name: After C# 14 + href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2011.md - name: After C# 13 href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2010.md - name: After C# 12 diff --git a/docs/csharp/whats-new/csharp-15.md b/docs/csharp/whats-new/csharp-15.md new file mode 100644 index 0000000000000..b4f7629ae414d --- /dev/null +++ b/docs/csharp/whats-new/csharp-15.md @@ -0,0 +1,32 @@ +--- +title: What's new in C# 15 +description: Get an overview of the new features in C# 15. C# 15 ships with .NET 11. +ms.date: 02/04/2025 +ms.topic: whats-new +ms.update-cycle: 365-days +--- +# What's new in C# 15 + +C# 15 includes the following new features. You can try these features using the latest [Visual Studio 2026](https://visualstudio.microsoft.com/) version or the [.NET 11 preview SDK](https://dotnet.microsoft.com/download/dotnet): + +- [Collection expression parameters](#collection-expression-parameters) + +C# 15 is the latest C# release. C# 15 is supported on **.NET 11**. For more information, see [C# language versioning](../language-reference/configure-language-version.md). + +You can download the latest .NET 11 preview SDK from the [.NET downloads page](https://dotnet.microsoft.com/download). You can also download [Visual Studio 2026 insiders](https://visualstudio.microsoft.com/vs/), which includes the .NET 11 preview SDK. + +New features are added to the "What's new in C#" page when they're available in public preview releases. The [working set](https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md#working-set) section of the [roslyn feature status page](https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md) tracks when upcoming features are merged into the main branch. + +You can find any breaking changes introduced in C# 15 in our article on [breaking changes](~/_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2011.md). + +[!INCLUDE [released-version-feedback](./includes/released-feedback.md)] + +## Collection expression parameters + +Next commit. + + From 6d8bc90bb26a57faf99cac4d4780352da1b8b062 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 3 Feb 2026 16:50:55 -0500 Subject: [PATCH 02/12] Publish the speclet as well Publish the feature speclet --- docfx.json | 4 +++- docs/csharp/specification/toc.yml | 2 ++ docs/csharp/whats-new/csharp-15.md | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docfx.json b/docfx.json index 472779e1a4754..fdf8600943b92 100644 --- a/docfx.json +++ b/docfx.json @@ -514,7 +514,7 @@ "_csharplang/proposals/csharp-12.0/*.md": "08/15/2023", "_csharplang/proposals/csharp-13.0/*.md": "10/31/2024", "_csharplang/proposals/csharp-14.0/*.md": "08/06/2025", - "_csharplang/proposals/*.md": "08/06/2025", + "_csharplang/proposals/*.md": "02/04/2025", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "11/08/2022", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "11/08/2023", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "11/09/2024", @@ -695,6 +695,7 @@ "_csharplang/proposals/csharp-14.0/ignored-directives.md": "Ignored preprocessor directives", "_csharplang/proposals/csharp-14.0/extension-operators.md": "Extension operators", "_csharplang/proposals/csharp-14.0/optional-and-named-parameters-in-expression-trees.md": "Optional and named parameters in expression trees", + "_csharplang/proposals/collection-expression-arguments.md": "Collection expression arguments", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12", @@ -822,6 +823,7 @@ "_csharplang/proposals/csharp-14.0/ignored-directives.md": "This proposal allows a source file to include ignored directives. In most cases, ignored directives are used for file-based apps, for example `#!`", "_csharplang/proposals/csharp-14.0/extension-operators.md": "This proposal extends the proposal for extensions to include *extension operators*, where an operator can be an extension member.", "_csharplang/proposals/csharp-14.0/optional-and-named-parameters-in-expression-trees.md": "This proposal allows an expression tree to include named and optional parameters. This enables expression trees to be more flexible in how they are constructed.", + "_csharplang/proposals/collection-expression-arguments.md": "This proposal introduces collection expression arguments.", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "Learn about any breaking changes since the initial release of C# 10 and included in C# 11", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "Learn about any breaking changes since the initial release of C# 11 and included in C# 12", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "Learn about any breaking changes since the initial release of C# 12 and included in C# 13", diff --git a/docs/csharp/specification/toc.yml b/docs/csharp/specification/toc.yml index bac4c4c1b2468..4b8ea3a7c984e 100644 --- a/docs/csharp/specification/toc.yml +++ b/docs/csharp/specification/toc.yml @@ -147,6 +147,8 @@ items: href: ../../../_csharplang/proposals/csharp-12.0/collection-expressions.md - name: Better conversion from collection expression href: ../../../_csharplang/proposals/csharp-13.0/collection-expressions-better-conversion.md + - name: Collection expression arguments + href: ../../../_csharplang/proposals/collection-expressions-arguments.md - name: Lambda discard parameters href: ../../../_csharplang/proposals/csharp-9.0/lambda-discard-parameters.md - name: Static anonymous functions diff --git a/docs/csharp/whats-new/csharp-15.md b/docs/csharp/whats-new/csharp-15.md index b4f7629ae414d..fe21cc55f3ec0 100644 --- a/docs/csharp/whats-new/csharp-15.md +++ b/docs/csharp/whats-new/csharp-15.md @@ -9,7 +9,7 @@ ms.update-cycle: 365-days C# 15 includes the following new features. You can try these features using the latest [Visual Studio 2026](https://visualstudio.microsoft.com/) version or the [.NET 11 preview SDK](https://dotnet.microsoft.com/download/dotnet): -- [Collection expression parameters](#collection-expression-parameters) +- [Collection expression arguments](#collection-expression-arguments) C# 15 is the latest C# release. C# 15 is supported on **.NET 11**. For more information, see [C# language versioning](../language-reference/configure-language-version.md). @@ -21,7 +21,7 @@ You can find any breaking changes introduced in C# 15 in our article on [breakin [!INCLUDE [released-version-feedback](./includes/released-feedback.md)] -## Collection expression parameters +## Collection expression arguments Next commit. From bca68226f9723da32d6f2f932f89169569e6c256 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 4 Feb 2026 10:25:01 -0500 Subject: [PATCH 03/12] update collection expression reference --- .../operators/collection-expressions.md | 53 ++++++++++++++++- .../shared/CollectionExpressionExamples.cs | 57 ++++++++++++++++++- .../snippets/shared/operators.csproj | 1 + docs/csharp/specification/toc.yml | 2 +- 4 files changed, 110 insertions(+), 3 deletions(-) diff --git a/docs/csharp/language-reference/operators/collection-expressions.md b/docs/csharp/language-reference/operators/collection-expressions.md index 5024f70e471f8..10ca22e9743fa 100644 --- a/docs/csharp/language-reference/operators/collection-expressions.md +++ b/docs/csharp/language-reference/operators/collection-expressions.md @@ -91,10 +91,61 @@ The `LineBuffer` type implements `IEnumerable`, so the compiler recognizes :::code language="csharp" source="./snippets/shared/CollectionExpressionExamples.cs" id="BuilderClass"::: -The `Create` method must return a `LineBuffer` object, and it must take a single parameter of the type `ReadOnlySpan`. The type parameter of the `ReadOnlySpan` must match the element type of the collection. A builder method that returns a generic collection has the generic `ReadOnlySpan` as its parameter. The method must be accessible and `static`. +The `Create` method must return a `LineBuffer` object, and it must take a final parameter of the type `ReadOnlySpan`. The type parameter of the `ReadOnlySpan` must match the element type of the collection. A builder method that returns a generic collection has the generic `ReadOnlySpan` as its parameter. The method must be accessible and `static`. + +Starting in C# 15, the `Create` method can have additional parameters before the `ReadOnlySpan` parameter. You can pass values to these parameters by using a `with(...)` element in the collection expression. See [Collection builder arguments](#collection-builder-arguments) for details. Finally, you must add the to the `LineBuffer` class declaration: :::code language="csharp" source="./snippets/shared/CollectionExpressionExamples.cs" id="BuilderAttribute"::: The first parameter provides the name of the *Builder* class. The second attribute provides the name of the builder method. + +## Collection expression arguments + +Starting in C# 15, you can pass arguments to the underlying collection's constructor or factory method by using a `with(...)` element as the first element in a collection expression. This feature enables you to specify capacity, comparers, or other constructor parameters directly within the collection expression syntax. + +The `with(...)` element must be the first element in the collection expression. The arguments declared in the `with(...)` element are passed to the appropriate constructor or create method based on the target type. + +### Constructor arguments + +When the target type is a class or struct that implements , the arguments in `with(...)` are passed to the constructor. The compiler uses overload resolution to select the best matching constructor: + +:::code language="csharp" source="./snippets/shared/CollectionExpressionExamples.cs" id="WithArgumentsExamples"::: + +In the preceding example: + +- The `List` constructor with a `capacity` parameter is called with `values.Length * 2`. +- The `HashSet` constructor with an parameter is called with `StringComparer.OrdinalIgnoreCase`. +- For interface target types like , the compiler creates a `List` with the specified capacity. + +### Collection builder arguments + +For types with a , the arguments declared in the `with(...)` element are passed to the create method *before* the `ReadOnlySpan` parameter. This allows create methods to accept configuration parameters: + +:::code language="csharp" source="./snippets/shared/CollectionExpressionExamples.cs" id="BuilderClassWithComparer"::: + +You can then use the `with(...)` element to pass the comparer: + +:::code language="csharp" source="./snippets/shared/CollectionExpressionExamples.cs" id="WithBuilderArgumentsExample"::: + +The create method is selected using overload resolution based on the arguments provided. The `ReadOnlySpan` containing the collection elements is always the last parameter. + +### Interface target types + +Collection expression arguments are supported for several interface target types. The following table shows the supported interfaces and their applicable constructor signatures: + +| Interface | Supported `with` elements | +|-----------|---------------------| +| , , | `()` (empty only) | +| , | `()`, `(int capacity)` | + +For and , the compiler uses a with the specified constructor. + +### Restrictions + +The `with(...)` element has the following restrictions: + +- It must be the first element in the collection expression. +- Arguments can't have `dynamic` type. +- It's not supported for arrays or span types (`Span`, `ReadOnlySpan`). diff --git a/docs/csharp/language-reference/operators/snippets/shared/CollectionExpressionExamples.cs b/docs/csharp/language-reference/operators/snippets/shared/CollectionExpressionExamples.cs index a96a8be5a77a9..0ae8bd140234b 100644 --- a/docs/csharp/language-reference/operators/snippets/shared/CollectionExpressionExamples.cs +++ b/docs/csharp/language-reference/operators/snippets/shared/CollectionExpressionExamples.cs @@ -2,7 +2,6 @@ using System.Runtime.CompilerServices; using System.Collections; - // [CollectionBuilder(typeof(LineBufferBuilder), "Create")] // @@ -55,6 +54,35 @@ internal static class LineBufferBuilder } // +// +internal static class MySetBuilder +{ + internal static MySet Create(ReadOnlySpan items) => new MySet(items); + internal static MySet Create(IEqualityComparer comparer, ReadOnlySpan items) => + new MySet(items, comparer); +} +// + +// +[CollectionBuilder(typeof(MySetBuilder), "Create")] +public class MySet : IEnumerable +{ + private readonly HashSet _set; + + public MySet(ReadOnlySpan items, IEqualityComparer? comparer = null) + { + _set = new HashSet(comparer); + foreach (var item in items) + { + _set.Add(item); + } + } + + public IEnumerator GetEnumerator() => _set.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} +// + public class CollectionExpressionExamples { internal static void Examples() @@ -124,5 +152,32 @@ public void Example() } // } + + // + public void CollectionArgumentsExamples() + { + string[] values = ["one", "two", "three"]; + + // Pass capacity argument to List constructor + List names = [with(capacity: values.Length * 2), .. values]; + + // Pass comparer argument to HashSet constructor + HashSet set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"]; + // set contains only one element because all strings are equal with OrdinalIgnoreCase + + // Pass capacity to IList (uses List constructor) + IList numbers = [with(capacity: 100), 1, 2, 3]; + } + // + + // + public void CollectionBuilderArgumentsExample() + { + // Pass comparer to a type with CollectionBuilder attribute + // The comparer argument is passed before the ReadOnlySpan parameter + MySet mySet = [with(StringComparer.OrdinalIgnoreCase), "A", "a", "B"]; + // mySet contains only two elements: "A" and "B" + } + // } diff --git a/docs/csharp/language-reference/operators/snippets/shared/operators.csproj b/docs/csharp/language-reference/operators/snippets/shared/operators.csproj index f4d23c3a13581..cf72e6c1ba500 100644 --- a/docs/csharp/language-reference/operators/snippets/shared/operators.csproj +++ b/docs/csharp/language-reference/operators/snippets/shared/operators.csproj @@ -3,6 +3,7 @@ Exe net10.0 + preview enable true true diff --git a/docs/csharp/specification/toc.yml b/docs/csharp/specification/toc.yml index 4b8ea3a7c984e..2286c56360af5 100644 --- a/docs/csharp/specification/toc.yml +++ b/docs/csharp/specification/toc.yml @@ -148,7 +148,7 @@ items: - name: Better conversion from collection expression href: ../../../_csharplang/proposals/csharp-13.0/collection-expressions-better-conversion.md - name: Collection expression arguments - href: ../../../_csharplang/proposals/collection-expressions-arguments.md + href: ../../../_csharplang/proposals/collection-expression-arguments.md - name: Lambda discard parameters href: ../../../_csharplang/proposals/csharp-9.0/lambda-discard-parameters.md - name: Static anonymous functions From 4c0db885f87312b38646e5f041c91365b46360f4 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 4 Feb 2026 10:32:25 -0500 Subject: [PATCH 04/12] Add arguments elements --- .../object-and-collection-initializers.md | 8 ++++++++ .../CollectionExpressionArguments.cs | 18 ++++++++++++++++++ .../object-collection-initializers.csproj | 3 ++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/CollectionExpressionArguments.cs diff --git a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md index ed0b8890f3cb8..186eb2530ba43 100644 --- a/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md +++ b/docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md @@ -188,6 +188,14 @@ The preceding sample generates code that calls the to add the three items into the dictionary. These two different ways to initialize associative collections have slightly different behavior because of the method calls the compiler generates. Both variants work with the `Dictionary` class. Other types might only support one or the other based on their public API. +### Collection expression arguments + +Starting in C# 15, you can use the `with(...)` element as the first element in a [collection expression](../../language-reference/operators/collection-expressions.md) to pass arguments to the collection's constructor. This feature enables you to specify capacity, comparers, or other constructor parameters directly within the collection expression syntax: + +:::code language="csharp" source="./snippets/object-collection-initializers/CollectionExpressionArguments.cs" id="CollectionExpressionWithArguments"::: + +For more information about collection expression arguments, including supported target types and restrictions, see [Collection expression arguments](../../language-reference/operators/collection-expressions.md#collection-expression-arguments). + ## Object Initializers with collection read-only property initialization Some classes might have collection properties where the property is read-only, like the `Cats` property of `CatOwner` in the following case: diff --git a/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/CollectionExpressionArguments.cs b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/CollectionExpressionArguments.cs new file mode 100644 index 0000000000000..18cebac9b26af --- /dev/null +++ b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/CollectionExpressionArguments.cs @@ -0,0 +1,18 @@ +namespace object_collection_initializers; + +public class CollectionExpressionArguments +{ + // + public static void CollectionExpressionWithArgumentsExample() + { + string[] values = ["one", "two", "three"]; + + // Use with() to pass capacity to the List constructor + List names = [with(capacity: values.Length * 2), .. values]; + + // Use with() to pass a comparer to the HashSet constructor + HashSet caseInsensitiveSet = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO"]; + // caseInsensitiveSet contains only one element because "Hello" and "HELLO" are equal + } + // +} diff --git a/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/object-collection-initializers.csproj b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/object-collection-initializers.csproj index f57e231d581e5..8c8d5872f45ee 100644 --- a/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/object-collection-initializers.csproj +++ b/docs/csharp/programming-guide/classes-and-structs/snippets/object-collection-initializers/object-collection-initializers.csproj @@ -2,7 +2,8 @@ Exe - net8.0 + net11.0 + 15 enable enable object_collection_initializers From 3e93500e200bb0b6a358be6218c6058a30964780 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 4 Feb 2026 10:35:04 -0500 Subject: [PATCH 05/12] Add information on collection expression arguments --- docs/csharp/whats-new/csharp-15.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/csharp/whats-new/csharp-15.md b/docs/csharp/whats-new/csharp-15.md index fe21cc55f3ec0..77fc124948428 100644 --- a/docs/csharp/whats-new/csharp-15.md +++ b/docs/csharp/whats-new/csharp-15.md @@ -23,7 +23,22 @@ You can find any breaking changes introduced in C# 15 in our article on [breakin ## Collection expression arguments -Next commit. +You can pass arguments to the underlying collection's constructor or factory method by using a `with(...)` element as the first element in a collection expression. This feature enables you to specify capacity, comparers, or other constructor parameters directly within the collection expression syntax. + +The following example shows how to pass a capacity argument to a `List` constructor and a comparer to a `HashSet`: + +```csharp +string[] values = ["one", "two", "three"]; + +// Pass capacity argument to List constructor +List names = [with(capacity: values.Length * 2), .. values]; + +// Pass comparer argument to HashSet constructor +HashSet set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"]; +// set contains only one element because all strings are equal with OrdinalIgnoreCase +``` + +You can learn more about collection expression arguments in the [language reference article on collection expressions](../language-reference/operators/collection-expressions.md#collection-expression-arguments) or the [feature specification](~/_csharplang/proposals/collection-expression-arguments.md). For information on using collection expression arguments in collection initializers, see [Object and Collection Initializers](../programming-guide/classes-and-structs/object-and-collection-initializers.md#collection-expression-arguments).