From 0266626cc787ed2385e4514fa33deb0967f05dd6 Mon Sep 17 00:00:00 2001 From: Kathleen Dollard Date: Thu, 3 Apr 2025 12:51:27 -0400 Subject: [PATCH 1/6] Initial draft of P3 release notes --- release-notes/10.0/preview/preview3/csharp.md | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 release-notes/10.0/preview/preview3/csharp.md diff --git a/release-notes/10.0/preview/preview3/csharp.md b/release-notes/10.0/preview/preview3/csharp.md new file mode 100644 index 0000000000..a01e6d4996 --- /dev/null +++ b/release-notes/10.0/preview/preview3/csharp.md @@ -0,0 +1,125 @@ +# C# 14 updates in .NET 10 Preview 3 - Release Notes + +Here's a summary of what's new in C# in this preview release: + +- [Extensions](#extensions) +- [Null-conditional assignment](#null-conditional-assignment) +- + +C# 14 updates: + +- [What's new in C# 14](https://learn.microsoft.com/dotnet/csharp/whats-new/csharp-14) documentation +- [Breaking changes in C# 14](https://learn.microsoft.com/dotnet/csharp/whats-new/breaking-changes/compiler%20breaking%20changes%20-%20dotnet%2010) + +## Extensions + +Extensions extend the extension methods you know and love to include support for static methods, instance properties and static properties in Preview 3. Look for even more members to have extension support in the near future! + +Extensions for other member types has been development for a long time because there are a couple of fundamental problems: how do declare extensions and how to disambiguate when more than one matching signature is available. We also wanted to support the new syntax for instance members and ensure that users of an instance extension method didn't need to worry about whether it was declared with the old or new syntax. + +Today you may have an extension method that follows the pattern: + +```csharp +public static class Extensions +{ + public static IEnumerable WhereGreaterThan(this IEnumerable source, int threshold) + => source.Where(x => x > threshold); +} +``` + +The _receiver_ is the parameter prefaced by the `this` keyword - `source` in this case. Property declaration do not have a similar location to declare the receiver. Thus, C# 14 introduces `extension` blocks. These are blocks with a scope that exposes the receive to its contained members. If we switch the `WhereGreaterThan` extension method to the new syntax and add an IsEmpty property the extension block would be: + +```csharp +public static class Extensions +{ + extension(IEnumerable source) + { + public IEnumerable WhereGreaterThan(int threshold) + => source.Where(x => x > threshold); + + public bool IsEmpty + => !source.Any(); + } +} +``` + +To use these members, you just call them: + +```csharp +var list = new List { 1, 2, 3, 4, 5 }; +var large = list.WhereGreaterThan(3); +if (large.IsEmpty) +{ + Console.WriteLine("No large numbers"); +} +else +{ + Console.WriteLine("Found large numbers"); +} +``` + +Generics are supported and the resolution rules are the same as for extension methods. For example, you could make `WhereGreaterThan` and `IsEmpty` generic: + +```csharp + extension(IEnumerable source) + where T: INumber + { + public IEnumerable WhereGreaterThan(T threshold) + => source.Where(x => x > threshold); + + public bool IsEmpty + => !source.Any(); + } +``` + +The constraint to `INumber` allows the greater than operator to be used. + +Static methods and properties don't have a receiver, so the extension block list the type without a parameter name: + +```csharp + extension(List) + { + public static List Create() + => []; + } +``` + +Our goals included extension blocks coexisting with the many extension methods you may have today. There's no need to change to the new syntax unless you want to - they execute in exactly the same manner. Extension blocks can be added to the static classes containing that contain your existing extension methods. + +You'll see more extensions in upcoming previews, but we'd love to hear your feedback at [](). + +## Null-conditional assignment + +Null-conditional assignment assign a value to a property or field only if the containing instance exists. Imagine you have a code similar to: + +```csharp +public class Customer +{ + public string Name { get; set; } + public int Age { get; set; } +} + +public class UpdateCustomer +{ + public static void UpdateAge(Customer? customer, int newAge) + { + if (customer is not null) + { + customer.Age = newAge; + } + } +} +``` + +You can simplify the `UpdateAge` method: + +```csharp + public static void UpdateAge(Customer? customer, int newAge) + { + customer?.Age = newAge; + } +``` + +If the customer is not null, `Age` will be updated. If customer is null, nothing will happen. + +The IDE will help you by recommending this change. From 429a1d6860507065779f8440ea8444ae1ec6ac70 Mon Sep 17 00:00:00 2001 From: Kathleen Dollard Date: Thu, 3 Apr 2025 13:10:33 -0700 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Cyrus Najmabadi Co-authored-by: Wendy Breiding <55603905+webreidi@users.noreply.github.com> --- release-notes/10.0/preview/preview3/csharp.md | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/release-notes/10.0/preview/preview3/csharp.md b/release-notes/10.0/preview/preview3/csharp.md index a01e6d4996..893e06870b 100644 --- a/release-notes/10.0/preview/preview3/csharp.md +++ b/release-notes/10.0/preview/preview3/csharp.md @@ -13,25 +13,25 @@ C# 14 updates: ## Extensions -Extensions extend the extension methods you know and love to include support for static methods, instance properties and static properties in Preview 3. Look for even more members to have extension support in the near future! +Extensions just got even more powerful! In Preview 3, they now support static methods, instance properties, and static properties—expanding the capabilities you already know and love. And this is just the beginning—stay tuned for even more extension support in an upcoming release! -Extensions for other member types has been development for a long time because there are a couple of fundamental problems: how do declare extensions and how to disambiguate when more than one matching signature is available. We also wanted to support the new syntax for instance members and ensure that users of an instance extension method didn't need to worry about whether it was declared with the old or new syntax. +Expanding extensions to other member types has been a long-standing challenge, driven by two key questions: how to declare them effectively and how to resolve ambiguity when multiple matching signatures exist. Additionally, we aimed to seamlessly support the new syntax for instance members—ensuring that users of instance extension methods never have to worry about whether they were declared with the old or new syntax. After extensive development, we’re bringing these solutions to life! Today you may have an extension method that follows the pattern: ```csharp public static class Extensions -{ +{ public static IEnumerable WhereGreaterThan(this IEnumerable source, int threshold) - => source.Where(x => x > threshold); + => source.Where(x => x > threshold); } ``` -The _receiver_ is the parameter prefaced by the `this` keyword - `source` in this case. Property declaration do not have a similar location to declare the receiver. Thus, C# 14 introduces `extension` blocks. These are blocks with a scope that exposes the receive to its contained members. If we switch the `WhereGreaterThan` extension method to the new syntax and add an IsEmpty property the extension block would be: +The _receiver_ is the parameter prefaced by the `this` keyword - `source` in this case. Property declarations do not have a similar location to declare the receiver. Thus, C# 14 introduces `extension` blocks. These are blocks with a scope that exposes the receiver to its contained members. If we switch the `WhereGreaterThan` extension method to the new syntax and add an IsEmpty property the extension block would be: ```csharp public static class Extensions -{ +{ extension(IEnumerable source) { public IEnumerable WhereGreaterThan(int threshold) @@ -62,7 +62,7 @@ Generics are supported and the resolution rules are the same as for extension me ```csharp extension(IEnumerable source) - where T: INumber + where T : INumber { public IEnumerable WhereGreaterThan(T threshold) => source.Where(x => x > threshold); @@ -84,13 +84,15 @@ Static methods and properties don't have a receiver, so the extension block list } ``` -Our goals included extension blocks coexisting with the many extension methods you may have today. There's no need to change to the new syntax unless you want to - they execute in exactly the same manner. Extension blocks can be added to the static classes containing that contain your existing extension methods. +Extension blocks can seamlessly coexist with the extension methods you have today. There's no requirement to switch to the new syntax - both execute in exactly the same way. Just add extension blocks to the static classes that contain your existing extension methods. + +The choice is entirely yours. If you prefer to leave your existing extension methods untouched, you absolutely can. But if you’d rather update your code for a consistent look and take advantage of the new syntax, that option is available too. And with tools like Visual Studio, converting to your preferred form has never been easier! You'll see more extensions in upcoming previews, but we'd love to hear your feedback at [](). ## Null-conditional assignment -Null-conditional assignment assign a value to a property or field only if the containing instance exists. Imagine you have a code similar to: +Null-conditional assignment assigns a value to a property or field only if the containing instance exists. Imagine you have a code similar to: ```csharp public class Customer @@ -122,4 +124,4 @@ You can simplify the `UpdateAge` method: If the customer is not null, `Age` will be updated. If customer is null, nothing will happen. -The IDE will help you by recommending this change. +The IDE will help you by recommending this change via a lightbulb. From db5b445938b8e2c22eaa8a7f4a171e431844ccb7 Mon Sep 17 00:00:00 2001 From: Kathleen Dollard Date: Thu, 3 Apr 2025 13:17:31 -0700 Subject: [PATCH 3/6] Apply suggestions from code review --- release-notes/10.0/preview/preview3/csharp.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/release-notes/10.0/preview/preview3/csharp.md b/release-notes/10.0/preview/preview3/csharp.md index 893e06870b..06bed9446f 100644 --- a/release-notes/10.0/preview/preview3/csharp.md +++ b/release-notes/10.0/preview/preview3/csharp.md @@ -88,7 +88,7 @@ Extension blocks can seamlessly coexist with the extension methods you have toda The choice is entirely yours. If you prefer to leave your existing extension methods untouched, you absolutely can. But if you’d rather update your code for a consistent look and take advantage of the new syntax, that option is available too. And with tools like Visual Studio, converting to your preferred form has never been easier! -You'll see more extensions in upcoming previews, but we'd love to hear your feedback at [](). +You'll see more extensions in upcoming previews, but we'd love to hear your feedback, so join the team and others in the community in the discussion [Extensions](https://github.com/dotnet/csharplang/discussions/8696).. ## Null-conditional assignment @@ -125,3 +125,5 @@ You can simplify the `UpdateAge` method: If the customer is not null, `Age` will be updated. If customer is null, nothing will happen. The IDE will help you by recommending this change via a lightbulb. + +We'd love your feedback on this feature so join us and others in the community in the discussion [Null-conditional assignment](https://github.com/dotnet/csharplang/discussions/8676). From 97d923b4ddd1a364eec0fb71c3ee6162c00d6255 Mon Sep 17 00:00:00 2001 From: Kathleen Dollard Date: Thu, 3 Apr 2025 13:22:20 -0700 Subject: [PATCH 4/6] Apply suggestions from code review --- release-notes/10.0/preview/preview3/csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-notes/10.0/preview/preview3/csharp.md b/release-notes/10.0/preview/preview3/csharp.md index 06bed9446f..88f05a88f0 100644 --- a/release-notes/10.0/preview/preview3/csharp.md +++ b/release-notes/10.0/preview/preview3/csharp.md @@ -2,7 +2,7 @@ Here's a summary of what's new in C# in this preview release: -- [Extensions](#extensions) +- [Extension members](#extension-members) - [Null-conditional assignment](#null-conditional-assignment) - From e0ccce6efe8f2a5523140c1c7c5811acc6eef230 Mon Sep 17 00:00:00 2001 From: Kathleen Dollard Date: Thu, 3 Apr 2025 13:23:14 -0700 Subject: [PATCH 5/6] Apply suggestions from code review --- release-notes/10.0/preview/preview3/csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-notes/10.0/preview/preview3/csharp.md b/release-notes/10.0/preview/preview3/csharp.md index 88f05a88f0..2d4b60fd3b 100644 --- a/release-notes/10.0/preview/preview3/csharp.md +++ b/release-notes/10.0/preview/preview3/csharp.md @@ -11,7 +11,7 @@ C# 14 updates: - [What's new in C# 14](https://learn.microsoft.com/dotnet/csharp/whats-new/csharp-14) documentation - [Breaking changes in C# 14](https://learn.microsoft.com/dotnet/csharp/whats-new/breaking-changes/compiler%20breaking%20changes%20-%20dotnet%2010) -## Extensions +## Extension members Extensions just got even more powerful! In Preview 3, they now support static methods, instance properties, and static properties—expanding the capabilities you already know and love. And this is just the beginning—stay tuned for even more extension support in an upcoming release! From 89e2f77b769c9f92a9d297f07c0bc14a21a2ffb5 Mon Sep 17 00:00:00 2001 From: Kathleen Dollard Date: Mon, 7 Apr 2025 12:58:10 -0700 Subject: [PATCH 6/6] Update release-notes/10.0/preview/preview3/csharp.md --- release-notes/10.0/preview/preview3/csharp.md | 1 - 1 file changed, 1 deletion(-) diff --git a/release-notes/10.0/preview/preview3/csharp.md b/release-notes/10.0/preview/preview3/csharp.md index 2d4b60fd3b..1178852dfe 100644 --- a/release-notes/10.0/preview/preview3/csharp.md +++ b/release-notes/10.0/preview/preview3/csharp.md @@ -4,7 +4,6 @@ Here's a summary of what's new in C# in this preview release: - [Extension members](#extension-members) - [Null-conditional assignment](#null-conditional-assignment) -- C# 14 updates: