{"id":46459,"date":"2023-07-11T10:11:00","date_gmt":"2023-07-11T17:11:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=46459"},"modified":"2023-07-18T11:07:54","modified_gmt":"2023-07-18T18:07:54","slug":"new-csharp-12-preview-features","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/new-csharp-12-preview-features\/","title":{"rendered":"New C# 12 preview features"},"content":{"rendered":"<p>Visual Studio 17.7 Preview 3 and .NET 8 Preview 6 continue the evolution of C# 12. This preview includes features designed to lay the groundwork for future performance enhancements. Easy access to inline arrays will allow libraries to use them in more places without effort on your part. This preview debuts an experimental feature called <em>interceptors<\/em> that allow generators to reroute code, such as to provide context specific optimization. Finally, <code>nameof<\/code> is enhanced to work in more places.<\/p>\n<p>You can get C# 12 by <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">installing the latest Visual Studio preview<\/a> or <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">the latest version of the .NET SDK<\/a>. To check out C# 12 features, you&#8217;ll need to set the language version of your project to preview:<\/p>\n<pre><code class=\"language-xml\">&lt;PropertyGroup&gt;\r\n   &lt;LangVersion&gt;preview&lt;\/LangVersion&gt;\r\n&lt;\/PropertyGroup&gt;<\/code><\/pre>\n<p>Since they are experimental, <a href=\"#interceptors\">interceptors require an additional flag<\/a> in your project file.<\/p>\n<h2><code>nameof<\/code> accessing instance members<\/h2>\n<p>The <code>nameof<\/code> keyword now works with member names, including initializers, on static members, and in attributes:<\/p>\n<pre><code class=\"language-c#\">internal class NameOf\r\n{\r\n    public string S { get; } = \"\";\r\n    public static int StaticField;\r\n    public string NameOfLength { get; } = nameof(S.Length);\r\n    public static void NameOfExamples()\r\n    {\r\n        Console.WriteLine(nameof(S.Length));\r\n        Console.WriteLine(nameof(StaticField.MinValue));\r\n    }\r\n    [Description($\"String {nameof(S.Length)}\")]\r\n    public int StringLength(string s)\r\n    { return s.Length; }\r\n}<\/code><\/pre>\n<p>You can learn more at <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/whats-new\/csharp-12\">What&#8217;s new in C# 12<\/a>.<\/p>\n<h2>Inline arrays<\/h2>\n<p>The <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/61135\">InlineArrayAttribute<\/a> was introduced to the runtime in a previous .NET 8 preview. This is an advanced feature that will be used primarily by the compiler, .NET libraries and some other libraries. The attribute identifies a type that can be treated as a contiguous sequence of primitives for efficient, type-safe, overrun-safe indexable\/sliceable inline data. The .NET libraries improve performance of your application and tools using inline arrays.<\/p>\n<p>The compiler creates different IL to access inline arrays. This results in a few restrictions, such as list patterns not being supported. In most cases, you access inline arrays the same as other arrays. The different IL creates performance gains without changing your code:<\/p>\n<pre><code class=\"language-c#\">private static void InlineArrayAccess(Buffer10&lt;int&gt; inlineArray)\r\n{\r\n    for (int i = 0; i &lt; 10; i++)\r\n    {\r\n        inlineArray[i] = i * i;\r\n    }\r\n    foreach (int i in inlineArray)\r\n    {\r\n        Console.WriteLine(i);\r\n    }\r\n}<\/code><\/pre>\n<p>Most folks will consume inline arrays, rather than create them. But, it&#8217;s nice to understand how things work. Inline arrays are fast because they rely on an exact layout of a specified length. An inline array is a type with a single field and marked with the <code>InlineArrayAttribute<\/code> that specifies the length of the array. In the type used in the previous example, the runtime creates storage for exactly ten elements in <code>Buffer10&lt;T&gt;<\/code> due to the attribute parameter:<\/p>\n<pre><code class=\"language-c#\">[System.Runtime.CompilerServices.InlineArray(10)]\r\npublic struct Buffer10&lt;T&gt;\r\n{\r\n    private T _element0;\r\n}<\/code><\/pre>\n<p>You can learn more at <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/whats-new\/csharp-12#inline-arrays\">What&#8217;s new in C# 12<\/a>.<\/p>\n<h2>Interceptors<\/h2>\n<p>This preview introduces an experimental feature called <em>interceptors<\/em>. It\u2019s intended for advanced scenarios, particularly allowing better ahead of time compilation (AOT). As an experimental part of .NET 8, it may be changed or removed in a future version. Thus, it should not be used in production.<\/p>\n<p>Interceptors allow specific method calls to be rerouted to different code. Attributes specify the actual source code location so interceptors are generally appropriate only for source generators. You can read the <a href=\"https:\/\/github.com\/dotnet\/csharplang\/issues\/7009\">interceptors proposal<\/a> to learn more about how interceptors work.<\/p>\n<p>Because interceptors are an experimental feature, you&#8217;ll need to explicitly enable them in your project file:<\/p>\n<pre><code class=\"language-xml\">&lt;PropertyGroup&gt;\r\n   &lt;Features&gt;InterceptorsPreview&lt;\/Features&gt;\r\n&lt;\/PropertyGroup&gt;<\/code><\/pre>\n<p>Interceptors enable exciting code patterns. A few examples are:<\/p>\n<ul>\n<li>Calls that are known at compile time, like <code>Regex.IsMatch(@\"a+b+\")<\/code> with a constant pattern can be intercepted to use statically-generated code for optimization that is friendly to AOT.<\/li>\n<li>ASP.NET Minimal API calls like <code>app.MapGet(\"\/products\", handler: (int? page, int? pageLength, MyDb db) =&gt; { ... })<\/code> can be intercepted to register a statically-generated thunk which calls the user&#8217;s handler directly, skipping an allocation and indirection.<\/li>\n<li>In vectorization, where foreach loops contain calls to user methods, the compiler can rewrite code to check for and use relevant intrinsics at runtime, but fall back to the original code if those intrinsics aren&#8217;t available.<\/li>\n<li>Static dependency graph resolution for dependency injection, where <code>provider.Register&lt;MyService&gt;()<\/code> can be intercepted.<\/li>\n<li>Calls to query providers could be intercepted to offer translation to another language (e.g. SQL) at compile time, rather than evaluating expression trees to translate at runtime.<\/li>\n<li>Serializers could generate type specific (de)serialization based on the concrete type of calls like <code>Serialize&lt;MyType&gt;()<\/code>, all at compile time.<\/li>\n<\/ul>\n<p>Most programmers will not use interceptors directly, but we hope they will play a significant role in our journey to make your applications run faster and be easier to deploy. Interceptors are expected to remain experimental in the C# 12\/.NET 8 release and may be included in a future version of C#.<\/p>\n<h2>Summary<\/h2>\n<p>You can find more information about all of the features introduced so far at the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/csharp\/whats-new\/csharp-12\">What&#8217;s new in C# 12 page of Microsoft Learn<\/a> and track the evolution of C# 12 features at the <a href=\"https:\/\/github.com\/dotnet\/roslyn\/blob\/main\/docs\/Language%20Feature%20Status.md\">Roslyn Feature Status page<\/a>.<\/p>\n<p>You can check out the latest C# 12 features by <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">downloading the latest Visual Studio preview<\/a> or <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/8.0\">the latest version of the .NET SDK<\/a>, and setting <code>LangVersion<\/code> to <code>preview<\/code> in your project file.<\/p>\n<p>Let us know what you think!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 8 Preview 6 adds three new features for C# 12: interceptors, inline arrays, and enhancements to the nameof expression.<\/p>\n","protected":false},"author":1097,"featured_media":46460,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,756],"tags":[7701,7727],"class_list":["post-46459","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-csharp","tag-dotnet-8","tag-c-12"],"acf":[],"blog_post_summary":"<p>.NET 8 Preview 6 adds three new features for C# 12: interceptors, inline arrays, and enhancements to the nameof expression.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/46459","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/1097"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=46459"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/46459\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/46460"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=46459"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=46459"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=46459"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}