{"id":4911,"date":"2026-08-24T17:30:04","date_gmt":"2026-08-24T17:30:04","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/08\/24\/explore-new-features-available-in-c-15-preview\/"},"modified":"2026-08-24T17:30:04","modified_gmt":"2026-08-24T17:30:04","slug":"explore-new-features-available-in-c-15-preview","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/08\/24\/explore-new-features-available-in-c-15-preview\/","title":{"rendered":"Explore new features available in C# 15 preview"},"content":{"rendered":"<p>C# 15 will ship with .NET 11 in November. All the new features are available in .NET 11 preview 7 for you to try now. C# 15 adds <em>union types<\/em>, <em>closed hierarchies<\/em>, the first preview of an updated <code>unsafe<\/code> model, collection expression arguments, extension indexers, and labeled <code>break<\/code> and <code>continue<\/code>. For more details on each of these features, see <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/whats-new\/csharp-15\">What\u2019s new in C# 15<\/a> and the articles linked from that page.<\/p>\n<h2>Union types<\/h2>\n<p>A <em>union type<\/em> lets you say, in the type system, exactly which types a value may hold. With <code>object<\/code>, a marker interface, or an abstract base class, the runtime type can still be anything derived from <code>object<\/code> or anything that implements or derives from the shared type. A union constrains the value to one of the specified <em>case types<\/em>. The case types in a union aren\u2019t necessarily related by inheritance. Use the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/explore-csharp-15\/#closed-hierarchies\">closed hierarchies<\/a> feature to restrict the set of types related by inheritance.<\/p>\n<pre><code class=\"language-csharp\">public record class Cat(string Name);\npublic record class Dog(string Name);\npublic record class Bird(string Name);\n\npublic union Pet(Cat, Dog, Bird);<\/code><\/pre>\n<p>A <code>Pet<\/code> holds a <code>Cat<\/code>, a <code>Dog<\/code>, or a <code>Bird<\/code>. Each case type converts implicitly to <code>Pet<\/code>. Because the compiler knows the complete set, a <code>switch<\/code> expression over a non-null <code>Pet<\/code> is exhaustive without a discard or default arm:<\/p>\n<pre><code class=\"language-csharp\">Pet pet = new Dog(\"Rex\");\n\nstring name = pet switch\n{\n    Dog d =&gt; d.Name,\n    Cat c =&gt; c.Name,\n    Bird b =&gt; b.Name,\n};<\/code><\/pre>\n<p>Union types are one expression of a broader design idea: make the allowed set of types explicit. <em>Closed hierarchies<\/em>, covered next, and the planned <em>closed enums<\/em> apply the same idea in other shapes.<\/p>\n<p>For more, read the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/csharp-15-union-types\/\">C# 15 union types<\/a> post, try the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/whats-new\/tutorials\/unions\">Work with union types<\/a> tutorial, and see the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/language-reference\/builtin-types\/union\">union types<\/a> reference.<\/p>\n<h2>Closed hierarchies<\/h2>\n<p><em>Closed hierarchies<\/em> apply the same idea to class hierarchies you design. The <code>closed<\/code> modifier on a class makes it implicitly <code>abstract<\/code>, and restricts its direct derived types to the declaring assembly. You declare which subtypes are allowed instead of leaving derivation open-ended. For example, you can model the states of a background job as records that derive from a closed base:<\/p>\n<pre><code class=\"language-csharp\">public closed record class JobStatus;\npublic record class Queued : JobStatus;\npublic record class Running(int PercentComplete) : JobStatus;\npublic record class Completed(TimeSpan Elapsed) : JobStatus;\npublic record class Failed(string Error) : JobStatus;<\/code><\/pre>\n<p>Closed hierarchies, union types, and the planned <em>closed enums<\/em> all express the allowed set of shapes directly in the type system. For rules, including how <code>closed<\/code> composes with inheritance, see the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/language-reference\/keywords\/closed\">closed modifier<\/a> and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/language-reference\/operators\/patterns#closed-hierarchy-patterns\">closed hierarchy patterns<\/a> references.<\/p>\n<h2>Memory-safety redesign (preview)<\/h2>\n<p>C# 15 starts a redesign of <code>unsafe<\/code>: from a syntax marker\u2014\u201dthere are pointers here\u201d\u2014to a contract the compiler can\u2019t verify and a developer upholds. This is a <strong>preview<\/strong> feature in .NET 11 and C# 15. The model and syntax might change for .NET 12 and C# 16. The current preview includes two language changes you can try. You need to opt in explicitly: add <code>&lt;Features&gt;$(Features);updated-memory-safety-rules&lt;\/Features&gt;<\/code> and <code>&lt;LangVersion&gt;preview&lt;\/LangVersion&gt;<\/code> to your project file.<\/p>\n<p>In the new model, pointer types no longer need an <code>unsafe<\/code> context. You can declare a pointer type, take an address with <code>&amp;<\/code>, use the <code>fixed<\/code> statement, convert a <code>stackalloc<\/code> to a pointer, and use <code>sizeof<\/code> on an unmanaged type in a safe context.<\/p>\n<p>Operations that dereference pointers still require <code>unsafe<\/code>: pointer indirection (<code>*p<\/code>), member access through a pointer (<code>p-&gt;m<\/code>), element access through a pointer (<code>p[i]<\/code>), fixed-size-buffer element access, and function-pointer invocation.<\/p>\n<p>Finally, when a member adds the <code>unsafe<\/code> modifier to its signature, that member can be called only in an <code>unsafe<\/code> context. This is a breaking change from the current semantics of <code>unsafe<\/code> on a member. The member is declaring that its callers must ensure that the contract is followed, or propagate the unsafety by also including the <code>unsafe<\/code> modifier in its declaration.<\/p>\n<p>Read <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/improving-csharp-memory-safety\/\">Improving C# memory safety<\/a> for the full model, and see the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/language-reference\/unsafe-code\">unsafe code<\/a> reference for the rules implemented in preview in C# 15.<\/p>\n\n<div class=\"alert alert-info\">\n<p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>Important<\/strong><\/p>\n<p>This is a preview feature in .NET 11 and C# 15. The design isn\u2019t final and will continue to evolve before it ships in its final form. We want people to try the preview behavior and <a href=\"https:\/\/github.com\/dotnet\/csharplang\">give us feedback in csharplang<\/a> so we can shape the final experience.<\/p><\/div>\n<h2>Collection expression arguments<\/h2>\n<p>Collection expressions convert to many collection types, but until now you couldn\u2019t pass arguments to the underlying constructor or <code>Create<\/code> method. C# 15 adds a <code>with(...)<\/code> element, written first, that forwards arguments to the constructor or factory method.<\/p>\n<p>This feature is necessary for the upcoming <em>dictionary expressions<\/em> syntax. You will often specify the comparer for a dictionary. You can use the feature now for sequence containers:<\/p>\n<pre><code class=\"language-csharp\">\/\/ Before\nList&lt;string&gt; names = new(capacity: values.Length * 2);\nnames.AddRange(values);\n\nvar set = new HashSet&lt;string&gt;(StringComparer.OrdinalIgnoreCase) { \"Hello\", \"HELLO\" };<\/code><\/pre>\n<pre><code class=\"language-csharp\">\/\/ After (C# 15)\nList&lt;string&gt; names = [with(capacity: values.Length * 2), .. values];\n\nHashSet&lt;string&gt; set = [with(StringComparer.OrdinalIgnoreCase), \"Hello\", \"HELLO\"];<\/code><\/pre>\n<p>Learn more in <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/language-reference\/operators\/collection-expressions#collection-expression-arguments\">collection expression arguments<\/a>.<\/p>\n<h2>Extension indexers<\/h2>\n<p>C# 14 introduced extension members: properties and operators alongside methods. C# 15 adds extension <em>indexers<\/em>, so you can index into a receiver as if the indexer were declared on its type. Indexers can\u2019t be static, so the extension container must include a named receiver.<\/p>\n<pre><code class=\"language-csharp\">\/\/ Before: a helper method\npublic static class SequenceExtensions\n{\n    public static int ElementAtIndex(this IEnumerable&lt;int&gt; sequence, int index)\n        =&gt; sequence.ElementAt(index);\n}\n\nint third = numbers.ElementAtIndex(2);<\/code><\/pre>\n<pre><code class=\"language-csharp\">\/\/ After (C# 15): an extension indexer\npublic static class SequenceExtensions\n{\n    extension(IEnumerable&lt;int&gt; sequence)\n    {\n        public int this[int index] =&gt; sequence.ElementAt(index);\n    }\n}\n\nint third = numbers[2];<\/code><\/pre>\n<p>Learn more in the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/language-reference\/keywords\/extension#extension-indexers\">extension indexers<\/a> reference.<\/p>\n<h2>Labeled break and continue<\/h2>\n<p>Breaking out of a nested loop usually means a flag, a <code>goto<\/code>, or an extracted method. With C# 15, you can label a loop and target it directly with <code>break<\/code> or <code>continue<\/code>.<\/p>\n<pre><code class=\"language-csharp\">\/\/ Before: a flag to unwind the outer loop\nbool found = false;\nforeach (Warehouse warehouse in warehouses)\n{\n    foreach (Bin bin in warehouse.Bins)\n    {\n        if (bin.Sku == requestedSku &amp;&amp; bin.Quantity &gt; 0)\n        {\n            reserved = Reserve(bin);\n            found = true;\n            break;\n        }\n    }\n    if (found)\n        break;\n}<\/code><\/pre>\n<pre><code class=\"language-csharp\">\/\/ After (C# 15): label the loop and break it directly\nscan: foreach (Warehouse warehouse in warehouses)\n{\n    foreach (Bin bin in warehouse.Bins)\n    {\n        if (bin.Sku == requestedSku &amp;&amp; bin.Quantity &gt; 0)\n        {\n            reserved = Reserve(bin);\n            break scan;\n        }\n    }\n}<\/code><\/pre>\n<p>The intent is in the code, with no flag to track. See the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/language-reference\/statements\/jump-statements\">jump statements<\/a> reference.<\/p>\n<h2>Try the preview<\/h2>\n<p>Download <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\">.NET 11<\/a> and try C# 15 on your apps. Read <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/whats-new\/csharp-15\">What\u2019s new in C# 15<\/a> for the complete reference and participate in the ongoing discussions in <a href=\"https:\/\/github.com\/dotnet\/csharplang\">csharplang<\/a>.<\/p>\n<p>The post <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/explore-csharp-15\/\">Explore new features available in C# 15 preview<\/a> appeared first on <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\">.NET Blog<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>C# 15 will ship with .NET 11 in November. All the new features are available in .NET 11 preview 7 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":94,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[7],"tags":[],"class_list":["post-4911","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/4911","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=4911"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/4911\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/94"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=4911"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=4911"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=4911"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}