{"id":33036,"date":"2021-05-25T07:59:43","date_gmt":"2021-05-25T14:59:43","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=33036"},"modified":"2021-05-25T21:16:15","modified_gmt":"2021-05-26T04:16:15","slug":"announcing-net-6-preview-4","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-6-preview-4\/","title":{"rendered":"Announcing .NET 6 Preview 4"},"content":{"rendered":"<p>We are delighted to release .NET 6 Preview 4. We&#8217;re now about half-way through the .NET 6 release. It&#8217;s a good moment to look again at the full scope of .NET 6, much like the <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-6-preview-1\/\">first preview post<\/a>. Many features are in close-to-final form and others will come soon now that the foundational building blocks are in place for the release. Preview 4 establishes a solid base for delivering a final .NET 6 build in November, with finished features and experiences. It&#8217;s also ready for real world testing if you haven&#8217;t yet tried .NET 6 in your environment.<\/p>\n<p>Speaking of the final release, we now have a date! Book off November 9-11 for <a href=\"https:\/\/www.dotnetconf.net\/\">.NET Conf 2021<\/a>. We&#8217;ll launch .NET 6 on the 9th with many in-depth talks and demos that tell you everything you want to know about .NET 6.<\/p>\n<p>You can <a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/6.0\">download .NET 6 Preview 4<\/a>, for Linux, macOS, and Windows.<\/p>\n<ul>\n<li><a href=\"https:\/\/dotnet.microsoft.com\/download\/dotnet\/6.0\">Installers and binaries<\/a><\/li>\n<li><a href=\"https:\/\/hub.docker.com\/_\/microsoft-dotnet\">Container images<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/blob\/main\/release-notes\/6.0\/install-linux.md\">Linux packages<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/blob\/main\/release-notes\/6.0\/README.md\">Release notes<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/blob\/main\/release-notes\/6.0\/known-issues.md\">Known issues<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/6295\">GitHub issue tracker<\/a><\/li>\n<\/ul>\n<p>See the <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/asp-net-core-updates-in-net-6-preview-4\">ASP.NET Core<\/a> and <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-entity-framework-core-6-0-preview-4-performance-edition\">EF Core<\/a> posts for more detail on what\u2019s new for web and data access scenarios. There&#8217;s also new <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-maui-preview-4\/\">.NET MAUI<\/a> post that describe new client app experiences and a <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/introducing-net-hot-reload\/\">Hot reload<\/a> post that describes a new approach to developer productivity.<\/p>\n<p>.NET 6 has been tested with <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/\">Visual Studio 16.11<\/a>\u00a0and <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/mac\/\">Visual Studio for Mac 8.9<\/a>. We recommend you use those builds if you want to try .NET 6 with <a href=\"https:\/\/visualstudio.microsoft.com\/\">Visual Studio<\/a>.<\/p>\n<h2>Build 2021<\/h2>\n<p>The <a href=\"https:\/\/build.microsoft.com\/\">Microsoft Build conference<\/a> is this week. It&#8217;s free and streaming on the web. It&#8217;s also not too late to register.<\/p>\n<p>You&#8217;ll want to checkout these talks for sure, which will include lots of discussion of .NET 6 and demos that show you what&#8217;s new and now possible.<\/p>\n<ul>\n<li><a href=\"https:\/\/aka.ms\/Build2021-BRK213\">The future of modern application development with .NET<\/a><\/li>\n<li><a href=\"https:\/\/aka.ms\/Build2021-OD485\">.NET 6 deep dive; what&#8217;s new and what&#8217;s coming<\/a><\/li>\n<li><a href=\"https:\/\/aka.ms\/Build2021-ATEBRK213\">.NET Team &#8220;Ask the Experts&#8221;<\/a><\/li>\n<\/ul>\n<h2>.NET 6 Themes<\/h2>\n<p>We started <a href=\"https:\/\/themesof.net\/\">planning .NET 6<\/a> in late 2020 on GitHub. We identified eight themes across a wide set of topics, including industry scenarios, support, and education. The themes represent half to three quarters of our effort for the release. There are many projects that don&#8217;t rise to the level of a theme or that are significant but not thematic (like <a href=\"https:\/\/github.com\/dotnet\/designs\/pull\/217\">supporting Apple Silicon<\/a> devices).<\/p>\n<p>The following are the .NET 6 themes, each described with a one sentence summary. They are listed in the same order they are displayed in <a href=\"https:\/\/themesof.net\/\">themesof.net<\/a>.<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5465\">.NET appeals to new developers, and students<\/a> &#8212; Deliver intentionally streamlined experiences in Visual Studio products, with clear docs, simpler code models with fewer files and concepts to learn, and intuitive paths to deploying artifacts to test and production environments.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5423\">.NET has a great client app development experience<\/a> &#8212; Deliver a cross-platform client app foundation that seamlessly caters to desktop, mobile, and web developers and that builds on and extends existing application types like Blazor, and Xamarin.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5397\">.NET is recognized as a compelling framework for building cloud native apps<\/a> &#8212; Deliver fundamental cloud-native features primarily aimed at performance and observability, improved integration with the cloud-native and <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/category\/containers\/\">container<\/a> ecosystems, and a cloud-native component (<a href=\"https:\/\/github.com\/microsoft\/reverse-proxy\">yarp<\/a>) that demonstrates much of the value of .NET with a critical cloud use case.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5238\">Enterprise and LTS<\/a> &#8212; Deliver simpler and more predictable models for using .NET with mission critical apps and better cater to the needs of large enterprise and government customers.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5415\">Grow the .NET ecosystem through increased Quality, Confidence, and Support<\/a> &#8212; Establish a long-term community collaboration that intends to elevate community developers to a similar level as Microsoft, and (on the flip-side) delivers new features and experiences that make it easier for enterprise developers to depend on libraries from community open source projects that are not necessarily affiliated with or backed by a large company.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5510\">Improve inner-loop performance for .NET developers<\/a> &#8212; Deliver developer productivity improvements that include improving build performance, Hot Restart and Hot Reload.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5491\">Improve startup and throughput using runtime execution information (PGO)<\/a> &#8212; Deliver a new model for improved performance based on runtime information that can be used for faster startup, higher throughput and smaller binaries.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5366\">Meeting Developer Expectations<\/a> &#8212; Deliver improvements across the .NET product based on feedback and to enable new scenarios with existing features.<\/li>\n<\/ul>\n<p>Some of these themes are discussed in more detail in the following posts:<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-6-preview-1\/\">.NET 6 Preview 1<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-6-preview-2\/\">.NET 6 Preview 2<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/conversation-about-pgo\/\">Conversation about PGO<\/a><\/li>\n<\/ul>\n<h2>.NET Platform unification<\/h2>\n<p>We&#8217;ve talked a lot in past posts and at conferences about <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/introducing-net-5\/\">.NET unification<\/a> yet it is missing from the themes. Platform unification is baked into everything we do and has no need for its own theme. One can think of it as being the one mega-theme above and beyond the ones that are listed. It is interleaved through multiple of the themes and is a basic assumption of the team going forward.<\/p>\n<p>The <a href=\"https:\/\/github.com\/dotnet\/core\/issues\/5510\">inner-loop performance project<\/a> is a great example. It assumes that .NET 6 apps all share the same foundation, for example using the same build system and libraries. Where there is a technical difference, like using a different runtime (CoreCLR or Mono) or code generation technique (AOT or JIT), we take those things into account and deliver pragmatic and appropriate experiences, with a bias to no observable experience difference. The <a href=\"https:\/\/github.com\/dotnet\/core\/issues\/6098#issuecomment-847257286\">EventPipe project<\/a> is another similar example.<\/p>\n<h2>Production confidence<\/h2>\n<p>We&#8217;ll soon start releasing &#8220;go live&#8221; builds that are supported in production. We&#8217;re currently targeting August for that. Our development model is oriented around enabling production workloads, even while we&#8217;re finishing up work on all the themes that were just mentioned.<\/p>\n<p>Production confidence begins with the <a href=\"https:\/\/dotnet.microsoft.com\/\">dotnet.microsoft.com<\/a> site. It&#8217;s been running half its site load on .NET 6 starting with Preview 1. While not massive scale, it is a mission critical site for our team and we take it very seriously. .NET 6 has been working for us like a champ.<\/p>\n<p>We also work with Microsoft teams who deploy their production apps on .NET previews. They do that so they can take advantage of new .NET features early. These teams are always looking for opportunities to reduce their cloud hosting costs, and deploying new .NET versions has proven to be one of the most effective and lowest effort approaches for that. These teams give us early feedback that helps us ensure new features are ready for global production use. They also significantly influence final feature shape because they are our first production users.<\/p>\n<p>All of this early battle-testing with real-world apps builds our confidence that .NET 6 will be ready for running your app.<\/p>\n<p>The remainder of the post is dedicated to features that are new in Preview 4.<\/p>\n<h2>Tools: Hot Reload with the Visual Studio debugger and <code>dotnet<\/code> CLI<\/h2>\n<p>Hot Reload is a new experience that enables you to make edits to your app&#8217;s source code while it is running without needing to manually pause the app or hit a breakpoint. Hot Reload improves developer productivity by reducing the number of times you need to restart your running app.<\/p>\n<p>With this release, Hot Reload works for many types of apps such as WPF, Windows Forms, WinUI, ASP.NET, Console Apps and other frameworks that are running on top of the CoreCLR runtime. We\u2019re also working to bring this technology to WebAssembly, iOS and Android apps that run on top of Mono, but this is still coming (in a later Preview).<\/p>\n<p>To start testing this feature install <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/preview\/\">Visual Studio 2019 version 16.11 Preview 1<\/a> and start your app with the Visual Studio debugger (F5). Once your app is running, you\u2019ll now have the new option to make code changes and apply them using the new \u201capply code changes\u201d button as illustrated below.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2021\/05\/hot-reload.gif\" alt=\".NET Hot Reload Apply Code Changes in Visual Studio 2019\" \/><\/p>\n<p>Note: Click the image to start the animation.<\/p>\n<p>Hot Reload is also available through the <code>dotnet watch<\/code> tool. Preview 4 includes multiple fixes that improve that experience.<\/p>\n<p>If you want to learn more about Hot Reload you can read <a href=\"https:\/\/aka.ms\/build2021-hotreload\">Introducing .NET Hot Reload<\/a>.<\/p>\n<h2>System.Text.Json support for IAsyncEnumerable<\/h2>\n<p><code>IAsyncEnumerable&lt;T&gt;<\/code> is an important feature that was added with .NET Core 3.0 and C# 8. The new <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/1570\">enhancements<\/a> enable <code>System.Text.Json<\/code> (de)serialization with <code>IAsyncEnumerable&lt;T&gt;<\/code> objects.<\/p>\n<p>The following examples use streams as a representation of any async source of data. The source could be files on a local machine, or results from a database query or web service API call.<\/p>\n<h3>Streaming serialization<\/h3>\n<p>System.Text.Json now supports serializing <code>IAsyncEnumerable&lt;T&gt;<\/code> values as JSON arrays, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">using System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Text.Json;\r\n\r\nstatic async IAsyncEnumerable&lt;int&gt; PrintNumbers(int n)\r\n{\r\n    for (int i = 0; i &lt; n; i++) yield return i;\r\n}\r\n\r\nusing Stream stream = Console.OpenStandardOutput();\r\nvar data = new { Data = PrintNumbers(3) };\r\nawait JsonSerializer.SerializeAsync(stream, data); \/\/ prints {\"Data\":[0,1,2]}<\/code><\/pre>\n<p><code>IAsyncEnumerable<\/code> values are only supported using the asynchronous serialization methods. Attempting to serialize using the synchronous methods will result in a <code>NotSupportedException<\/code> being thrown.<\/p>\n<h3>Streaming deserialization<\/h3>\n<p>Streaming deserialization required a new API that returns <code>IAsyncEnumerable&lt;T&gt;<\/code>. We added the <code>JsonSerializer.DeserializeAsyncEnumerable<\/code> method for this purpose, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">using System;\r\nusing System.IO;\r\nusing System.Text;\r\nusing System.Text.Json;\r\n\r\nvar stream = new MemoryStream(Encoding.UTF8.GetBytes(\"[0,1,2,3,4]\"));\r\nawait foreach (int item in JsonSerializer.DeserializeAsyncEnumerable&lt;int&gt;(stream))\r\n{\r\n    Console.WriteLine(item);\r\n}<\/code><\/pre>\n<p>This example will deserialize elements on-demand and can be useful when consuming particularly large data streams. It only supports reading from root-level JSON arrays, although that could be relaxed in the future based on feedback.<\/p>\n<p>The existing <code>DeserializeAsync<\/code> method nominally supports <code>IAsyncEnumerable&lt;T&gt;<\/code>, but within the confines of its non-streaming method signature. It must return the final result as a single value, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">using System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Text;\r\nusing System.Text.Json;\r\n\r\nvar stream = new MemoryStream(Encoding.UTF8.GetBytes(@\"{\"\"Data\"\":[0,1,2,3,4]}\"));\r\nvar result = await JsonSerializer.DeserializeAsync&lt;MyPoco&gt;(stream);\r\nawait foreach (int item in result.Data)\r\n{\r\n    Console.WriteLine(item);\r\n}\r\n\r\npublic class MyPoco\r\n{\r\n    public IAsyncEnumerable&lt;int&gt; Data { get; set; }\r\n}<\/code><\/pre>\n<p>In this example, the deserializer will have buffered all <code>IAsyncEnumerable<\/code> contents in memory before returning the deserialized object. This is because the deserializer needs to have consumed the entire JSON value before returning a result.<\/p>\n<h2>System.Text.Json: Writable DOM Feature<\/h2>\n<p>The <a href=\"https:\/\/github.com\/dotnet\/designs\/blob\/main\/accepted\/2020\/serializer\/WriteableDomAndDynamic.md\">writeable JSON DOM feature<\/a> adds a new straightforward and high-performance programming model for <code>System.Text.Json<\/code>. This new API is attractive since it avoids the complexity and ceremony of serialization and the traditional cost of a DOM.<\/p>\n<p>This new API has the following benefits:<\/p>\n<ul>\n<li>A lightweight alternative to serialization for cases when use of POCO types is not possible or desired, or when a JSON schema is not fixed and must be inspected.<\/li>\n<li>Enables efficient modification of a subset of a large tree. For example, it is possible to efficiently navigate to a subsection of a large JSON tree and read an array or deserialize a POCO from that subsection. LINQ can also be used with that.<\/li>\n<li>Enables using the C# <code>dynamic<\/code> keyword, which allows for a loosely-typed, more script-like model.<\/li>\n<\/ul>\n<p>We&#8217;re looking for <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/53195\">feedback on support for <code>dynamic<\/code><\/a>. Please give us your feedback if <code>dynamic<\/code> support is important to you.<\/p>\n<p>More details are available at <a href=\"https:\/\/github.com\/dotnet\/core\/issues\/6098#issuecomment-840857013\">dotnet\/runtime #6098<\/a>.<\/p>\n<h3>Writeable DOM APIs<\/h3>\n<p>The writeable DOM exposes the following types.<\/p>\n<pre><code class=\"language-cs\">namespace System.Text.Json.Node\r\n{\r\n    public abstract class JsonNode {...};\r\n    public sealed class JsonObject : JsonNode, IDictionary&lt;string, JsonNode?&gt; {...}\r\n    public sealed class JsonArray : JsonNode, IList&lt;JsonNode?&gt; {...};\r\n    public abstract class JsonValue : JsonNode {...};\r\n}<\/code><\/pre>\n<h3>Example code<\/h3>\n<p>The following example demonstrates the new programming model.<\/p>\n<pre><code class=\"language-cs\">    \/\/ Parse a JSON object\r\n    JsonNode jNode = JsonNode.Parse(\"{\"MyProperty\":42}\");\r\n    int value = (int)jNode[\"MyProperty\"];\r\n    Debug.Assert(value == 42);\r\n    \/\/ or\r\n    value = jNode[\"MyProperty\"].GetValue&lt;int&gt;();\r\n    Debug.Assert(value == 42);\r\n\r\n    \/\/ Parse a JSON array\r\n    jNode = JsonNode.Parse(\"[10,11,12]\");\r\n    value = (int)jNode[1];\r\n    Debug.Assert(value == 11);\r\n    \/\/ or\r\n    value = jNode[1].GetValue&lt;int&gt;();\r\n    Debug.Assert(value == 11);\r\n\r\n    \/\/ Create a new JsonObject using object initializers and array params\r\n    var jObject = new JsonObject\r\n    {\r\n        [\"MyChildObject\"] = new JsonObject\r\n        {\r\n            [\"MyProperty\"] = \"Hello\",\r\n            [\"MyArray\"] = new JsonArray(10, 11, 12)\r\n        }\r\n    };\r\n\r\n    \/\/ Obtain the JSON from the new JsonObject\r\n    string json = jObject.ToJsonString();\r\n    Console.WriteLine(json); \/\/ {\"MyChildObject\":{\"MyProperty\":\"Hello\",\"MyArray\":[10,11,12]}}\r\n\r\n    \/\/ Indexers for property names and array elements are supported and can be chained\r\n    Debug.Assert(jObject[\"MyChildObject\"][\"MyArray\"][1].GetValue&lt;int&gt;() == 11);<\/code><\/pre>\n<h2>Microsoft.Extensions.Logging compile-time source generator<\/h2>\n<p>.NET 6 introduces the <code>LoggerMessageAttribute<\/code> type. This attribute is part of the <code>Microsoft.Extensions.Logging<\/code> namespace, and when used, it source-generates performant logging APIs. The source-generation logging support is designed to deliver a highly usable and highly performant logging solution for modern .NET applications. The auto-generated source code relies on the <code>ILogger<\/code> interface in conjunction with <code>LoggerMessage.Define<\/code> functionality.<\/p>\n<p>The source generator is triggered when <code>LoggerMessageAttribute<\/code> is used on <code>partial<\/code> logging methods. When triggered, it is either able to autogenerate the implementation of the <code>partial<\/code> methods it&#8217;s decorating, or produce compile-time diagnostics with hints about proper usage. The compile-time logging solution is typically considerably faster at run time than existing logging approaches. It achieves this by eliminating boxing, temporary allocations, and copies to the maximum extent possible.<\/p>\n<p>There are benefits over manually using <code>LoggerMessage.Define<\/code> APIs directly:<\/p>\n<ul>\n<li>Shorter and simpler syntax: Declarative attribute usage rather than coding boilerplate.<\/li>\n<li>Guided developer experience: The generator gives warnings to help developers do the right thing.<\/li>\n<li>Support for an arbitrary number of logging parameters. <code>LoggerMessage.Define<\/code> supports a maximum of six.<\/li>\n<li>Support for dynamic log level. This is not possible with <code>LoggerMessage.Define<\/code> alone.<\/li>\n<\/ul>\n<p>If you would like to keep track of improvements and known issues, see <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/52549\">dotnet\/runtime#52549<\/a>.<\/p>\n<h3>Basic usage<\/h3>\n<p>To use the <code>LoggerMessageAttribute<\/code>, the consuming class and method need to be <code>partial<\/code>. The code generator is triggered at compile time, and generates an implementation of the <code>partial<\/code> method.<\/p>\n<pre><code class=\"language-csharp\">public static partial class Log\r\n{\r\n    [LoggerMessage(EventId = 0, Level = LogLevel.Critical, Message = \"Could not open socket to `{hostName}`\")]\r\n    public static partial void CouldNotOpenSocket(ILogger logger, string hostName);\r\n}<\/code><\/pre>\n<p>In the preceding example, the logging method is <code>static<\/code> and the log level is specified in the attribute definition. When using the attribute in a static context, the <code>ILogger<\/code> instance is required as a parameter. You may choose to use the attribute in a non-static context as well. For more examples and usage scenarios visit the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/core\/extensions\/logger-message-generator\">docs<\/a> for the compile-time logging source generator.<\/p>\n<h2>System.Linq enhancements<\/h2>\n<p><a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/47231\">New System.LINQ APIs<\/a> have been added that have been requested and contributed by the community.<\/p>\n<h3>Enumerable support for <code>Index<\/code> and <code>Range<\/code> parameters<\/h3>\n<p>The <code>Enumerable.ElementAt<\/code> method now accepts indices from the end of the enumerable, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">Enumerable.Range(1, 10).ElementAt(^2); \/\/ returns 9<\/code><\/pre>\n<p>An <code>Enumerable.Take<\/code> overload has been added that accepts <code>Range<\/code> parameters. It simplifies taking slices of enumerable sequences:<\/p>\n<ul>\n<li><code>source.Take(..3)<\/code> instead of <code>source.Take(3)<\/code><\/li>\n<li><code>source.Take(3..)<\/code> instead of <code>source.Skip(3)<\/code><\/li>\n<li><code>source.Take(2..7)<\/code> instead of <code>source.Take(7).Skip(2)<\/code><\/li>\n<li><code>source.Take(^3..)<\/code> instead of <code>source.TakeLast(3)<\/code><\/li>\n<li><code>source.Take(..^3)<\/code> instead of <code>source.SkipLast(3)<\/code><\/li>\n<li><code>source.Take(^7..^3)<\/code> instead of <code>source.TakeLast(7).SkipLast(3)<\/code>.<\/li>\n<\/ul>\n<p>Credit to <a href=\"https:\/\/github.com\/dixin\">@dixin<\/a> for contributing the implementation.<\/p>\n<h3><code>TryGetNonEnumeratedCount<\/code><\/h3>\n<p>The <code>TryGetNonEnumeratedCount<\/code> method attempts to obtain the count of the source enumerable without forcing an enumeration. This approach can be useful in scenarios where it is useful to preallocate buffers ahead of enumeration, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">List&lt;T&gt; buffer = source.TryGetNonEnumeratedCount(out int count) ? new List&lt;T&gt;(capacity: count) : new List&lt;T&gt;();\r\nforeach (T item in source)\r\n{\r\n    buffer.Add(item);\r\n}<\/code><\/pre>\n<p><code>TryGetNonEnumeratedCount<\/code> checks for sources implementing <code>ICollection<\/code>\/<code>ICollection&lt;T&gt;<\/code> or takes advantage of some of the <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/a123d28793ad22954ca6d9074f43b540d0d30b43\/src\/libraries\/System.Linq\/src\/System\/Linq\/IIListProvider.cs\">internal optimizations employed by Linq<\/a>.<\/p>\n<h3><code>DistinctBy<\/code>\/<code>UnionBy<\/code>\/<code>IntersectBy<\/code>\/<code>ExceptBy<\/code><\/h3>\n<p>New variants have been added to the set operations that allow specifying equality using key selector functions, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">Enumerable.Range(1, 20).DistinctBy(x =&gt; x % 3); \/\/ {1, 2, 3}\r\n\r\nvar first = new (string Name, int Age)[] { (\"Francis\", 20), (\"Lindsey\", 30), (\"Ashley\", 40) };\r\nvar second = new (string Name, int Age)[] { (\"Claire\", 30), (\"Pat\", 30), (\"Drew\", 33) };\r\nfirst.UnionBy(second, person =&gt; person.Age); \/\/ { (\"Francis\", 20), (\"Lindsey\", 30), (\"Ashley\", 40), (\"Drew\", 33) }<\/code><\/pre>\n<h3><code>MaxBy<\/code>\/<code>MinBy<\/code><\/h3>\n<p><code>MaxBy<\/code> and <code>MinBy<\/code> methods allow finding maximal or minimal elements using a key selector, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">var people = new (string Name, int Age)[] { (\"Francis\", 20), (\"Lindsey\", 30), (\"Ashley\", 40) };\r\npeople.MaxBy(person =&gt; person.Age); \/\/ (\"Ashley\", 40)<\/code><\/pre>\n<h3><code>Chunk<\/code><\/h3>\n<p><code>Chunk<\/code> can be used to chunk a source enumerable into slices of a fixed size, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">IEnumerable&lt;int[]&gt; chunks = Enumerable.Range(0, 10).Chunk(size: 3); \/\/ { {0,1,2}, {3,4,5}, {6,7,8}, {9} }<\/code><\/pre>\n<p>Credit to <a href=\"https:\/\/github.com\/inputfalken\">Robert Andersson<\/a> for contributing the implementation.<\/p>\n<h3><code>FirstOrDefault<\/code>\/<code>LastOrDefault<\/code>\/<code>SingleOrDefault<\/code> overloads taking default parameters<\/h3>\n<p>The existing <code>FirstOrDefault<\/code>\/<code>LastOrDefault<\/code>\/<code>SingleOrDefault<\/code> methods return <code>default(T)<\/code> if the source enumerable is empty. New overloads have been added that accept a default parameter to be returned in that case, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">Enumerable.Empty&lt;int&gt;().SingleOrDefault(-1); \/\/ returns -1<\/code><\/pre>\n<p>Credit to <a href=\"https:\/\/github.com\/Foxtrek64\">@Foxtrek64<\/a> for contributing the implementation.<\/p>\n<h3><code>Zip<\/code> overload accepting three enumerables<\/h3>\n<p>The <a href=\"https:\/\/docs.microsoft.com\/dotnet\/api\/system.linq.enumerable.zip\">Zip<\/a> method now supports combining three enumerables, as you can see in the following example.<\/p>\n<pre><code class=\"language-csharp\">var xs = Enumerable.Range(1, 10);\r\nvar ys = xs.Select(x =&gt; x.ToString());\r\nvar zs = xs.Select(x =&gt; x % 2 == 0);\r\n\r\nforeach ((int x, string y, bool z) in Enumerable.Zip(xs,ys,zs))\r\n{\r\n}<\/code><\/pre>\n<p>Credit to <a href=\"https:\/\/github.com\/huoyaoyuan\">Huo Yaoyuan<\/a> for contributing the implementation.<\/p>\n<h2>Significantly improved FileStream performance on Windows<\/h2>\n<p><code>FileStream<\/code> has been re-written in .NET 6, to have much higher performance and reliability on Windows.<\/p>\n<p>The <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/40359\">re-write project<\/a> has been phased over five PRs:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/47128\">Introduce FileStreamStrategy as a first step of FileStream rewrite<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/48813\">FileStream rewrite part II<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/49975\">FileStream optimizations<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50802\">FileStream rewrite: Use IValueTaskSource instead of TaskCompletionSource<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/51363\">FileStream rewrite: Caching the ValueTaskSource in AsyncWindowsFileStreamStrategy<\/a><\/li>\n<\/ul>\n<p>The final result is that <code>FileStream<\/code> never blocks when created for async IO, on Windows. That&#8217;s a major improvement. You can observe that in the benchmarks, which we&#8217;ll look at shortly.<\/p>\n<h3>Configuration<\/h3>\n<p>The first PR enables <code>FileStream<\/code> to choose an implementation at runtime. The most obvious benefit of this pattern is enabling switching back to the old .NET 5 implementation, which you can do with the following setting, in <code>runtimeconfig.json<\/code>.<\/p>\n<pre><code class=\"language-json\">{\r\n    \"configProperties\": {\r\n        \"System.IO.UseNet5CompatFileStream\": true\r\n    }\r\n}<\/code><\/pre>\n<p>We plan to add an <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/51985\"><code>io_uring<\/code> strategy<\/a> next, which takes advantage of a Linux feature by the same name in <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/51985#issuecomment-841907674\">recent kernels<\/a>.<\/p>\n<h3>Performance benchmark<\/h3>\n<p>Let&#8217;s measure the improvements using <a href=\"https:\/\/github.com\/dotnet\/BenchmarkDotNet\">BenchmarkDotNet<\/a>.<\/p>\n<pre><code class=\"language-csharp\">public class FileStreamPerf\r\n{\r\n    private const int FileSize = 1_000_000; \/\/ 1 MB\r\n    private Memory&lt;byte&gt; _buffer = new byte[8_000]; \/\/ 8 kB\r\n\r\n    [GlobalSetup(Target = nameof(ReadAsync))]\r\n    public void SetupRead() =&gt; File.WriteAllBytes(\"file.txt\", new byte[FileSize]);\r\n\r\n    [Benchmark]\r\n    public async ValueTask ReadAsync()\r\n    {\r\n        using FileStream fileStream = new FileStream(\"file.txt\", FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true);\r\n        while (await fileStream.ReadAsync(_buffer) &gt; 0)\r\n        {\r\n        }\r\n    }\r\n\r\n    [Benchmark]\r\n    public async ValueTask WriteAsync()\r\n    {\r\n        using FileStream fileStream = new FileStream(\"file.txt\", FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true);\r\n        for (int i = 0; i &lt; FileSize \/ _buffer.Length; i++)\r\n        {\r\n            await fileStream.WriteAsync(_buffer);\r\n        }\r\n    }\r\n\r\n    [GlobalCleanup]\r\n    public void Cleanup() =&gt; File.Delete(\"file.txt\");\r\n}\r\n\r\n```ini\r\nBenchmarkDotNet=v0.13.0, OS=Windows 10.0.18363.1500 (1909\/November2019Update\/19H2)\r\nIntel Xeon CPU E5-1650 v4 3.60GHz, 1 CPU, 12 logical and 6 physical cores\r\n.NET SDK=6.0.100-preview.5.21267.9\r\n  [Host]     : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT\r\n  Job-OIMCTV : .NET 5.0.6 (5.0.621.22011), X64 RyuJIT\r\n  Job-CHFNUY : .NET 6.0.0 (6.0.21.26311), X64 RyuJIT<\/code><\/pre>\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Runtime<\/th>\n<th style=\"text-align: right;\">Mean<\/th>\n<th style=\"text-align: right;\">Ratio<\/th>\n<th style=\"text-align: right;\">Allocated<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>ReadAsync<\/td>\n<td>.NET 5.0<\/td>\n<td style=\"text-align: right;\">3.785 ms<\/td>\n<td style=\"text-align: right;\">1.00<\/td>\n<td style=\"text-align: right;\">39 KB<\/td>\n<\/tr>\n<tr>\n<td>ReadAsync<\/td>\n<td>.NET 6.0<\/td>\n<td style=\"text-align: right;\">1.762 ms<\/td>\n<td style=\"text-align: right;\">0.47<\/td>\n<td style=\"text-align: right;\">1 KB<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td style=\"text-align: right;\"><\/td>\n<td style=\"text-align: right;\"><\/td>\n<td style=\"text-align: right;\"><\/td>\n<\/tr>\n<tr>\n<td>WriteAsync<\/td>\n<td>.NET 5.0<\/td>\n<td style=\"text-align: right;\">12.573 ms<\/td>\n<td style=\"text-align: right;\">1.00<\/td>\n<td style=\"text-align: right;\">39 KB<\/td>\n<\/tr>\n<tr>\n<td>WriteAsync<\/td>\n<td>.NET 6.0<\/td>\n<td style=\"text-align: right;\">3.200 ms<\/td>\n<td style=\"text-align: right;\">0.25<\/td>\n<td style=\"text-align: right;\">1 KB<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Environment:<\/strong> Windows 10 with SSD drive with BitLocker enabled<\/p>\n<p><strong>Results:<\/strong><\/p>\n<ul>\n<li>Reading 1 MB file is now <strong>2 times faster<\/strong>, while writing is <strong>4 times faster<\/strong>.<\/li>\n<li>Memory allocations dropped from 39 kilobytes to 1 kilobyte! This is a <strong>97.5% improvement<\/strong>!<\/li>\n<\/ul>\n<p>These changes should provide a dramatic improvement for <code>FileStream<\/code> users on Windows. More details are available at <a href=\"https:\/\/github.com\/dotnet\/core\/issues\/6098#issuecomment-830154834\">dotnet\/core #6098<\/a>.<\/p>\n<h2>Enhanced Date, Time and Time Zone support<\/h2>\n<p>The following <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/45318\">improvements<\/a> have been made to date and time related types.<\/p>\n<h3>New <code>DateOnly<\/code> and <code>TimeOnly<\/code> structs<\/h3>\n<p><a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/49036\">Date- and time-only structs<\/a> have been added, with the following characteristics:<\/p>\n<ul>\n<li>Each represent one half of a <code>DateTime<\/code>, either only the date part, or only the time part.<\/li>\n<li><code>DateOnly<\/code> is ideal for birthdays, anniversary days, and business days. It aligns with SQL Server&#8217;s <code>date<\/code> type.<\/li>\n<li><code>TimeOnly<\/code> is ideal for recurring meetings, alarm clocks, and weekly business hours. It aligns with SQL Server&#8217;s <code>time<\/code> type.<\/li>\n<li>Complements existing date\/time types (<code>DateTime<\/code>, <code>DateTimeOffset<\/code>, <code>TimeSpan<\/code>, <code>TimeZoneInfo<\/code>).<\/li>\n<li>In <code>System<\/code> namespace, shipped in CoreLib, just like existing related types.<\/li>\n<\/ul>\n<h3>Perf improvements to <code>DateTime.UtcNow<\/code><\/h3>\n<p>This <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50263\">improvement<\/a> has the following benefits:<\/p>\n<ul>\n<li>Fixes <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/13091\">2.5x perf regression<\/a> for getting the system time on Windows.<\/li>\n<li>Utilizes a 5-minute sliding cache of Windows leap second data instead of fetching with every call.<\/li>\n<\/ul>\n<h3>Support for both Windows and IANA time zones on all platforms<\/h3>\n<p>This improvements has the following benefits:<\/p>\n<ul>\n<li>Implicit conversion when using <code>TimeZoneInfo.FindSystemTimeZoneById<\/code> (https:\/\/github.com\/dotnet\/runtime\/pull\/49412)<\/li>\n<li>Explicit conversion through new APIs on <code>TimeZoneInfo<\/code>: <code>TryConvertIanaIdToWindowsId<\/code>, <code>TryConvertWindowsIdToIanaId<\/code>, and <code>HasIanaId<\/code> (https:\/\/github.com\/dotnet\/runtime\/issues\/49407)<\/li>\n<li>Improves cross-plat support and interop between systems that use different time zone types.<\/li>\n<li>Removes need to use TimeZoneConverter OSS library. The functionality is now built-in.<\/li>\n<\/ul>\n<h3>Improved time zone display names<\/h3>\n<p>This <a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/48931\">improvement<\/a> has the following benefits:<\/p>\n<ul>\n<li>Removes ambiguity from the display names in the list returned by <code>TimeZoneInfo.GetSystemTimeZones<\/code>.<\/li>\n<li>Leverages ICU \/ CLDR globalization data.<\/li>\n<li>Unix only for now. Windows still uses the registry data. This may be changed later.<\/li>\n<\/ul>\n<h3>Other<\/h3>\n<ul>\n<li>The UTC time zone&#8217;s display name and standard name were hardcoded to English and now uses the same language as the rest of the time zone data (<code>CurrentUICulture<\/code> on Unix, OS default language on Windows).<\/li>\n<li>Time zone display names in WASM use the non-localized IANA ID instead, due to size limitations.<\/li>\n<li><code>TimeZoneInfo.AdjustmentRule<\/code> nested class gets its <code>BaseUtcOffsetDelta<\/code> internal property made public, and gets a new constructor that takes <code>baseUtcOffsetDelta<\/code> as a parameter. (https:\/\/github.com\/dotnet\/runtime\/issues\/50256)<\/li>\n<li><code>TimeZoneInfo.AdjustmentRule<\/code> also gets misc fixes for loading time zones on Unix (https:\/\/github.com\/dotnet\/runtime\/pull\/49733), (https:\/\/github.com\/dotnet\/runtime\/pull\/50131)<\/li>\n<\/ul>\n<h2>CodeGen<\/h2>\n<p>The following improvements have been made to the RyuJIT compiler.<\/p>\n<h3>Community contributions<\/h3>\n<p><a href=\"https:\/\/github.com\/SingleAccretion\">@SingleAccretion<\/a> has been busy making the following improvements over the last few months. That is in addition to a contribution in <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/announcing-net-6-preview-3\/#runtime-codegen\">.NET 6 Preview 3<\/a>. Thanks!<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50373\">dotnet\/runtime #50373<\/a> &#8212; Do not fold away double negation if the tree is a CSE candidate<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50450\">dotnet\/runtime #50450<\/a> &#8212; Handle casts done via helpers and fold overflow operations in value numbering<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50702\">dotnet\/runtime #50702<\/a> &#8212; Remove must-init requirement for GS Cookies<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50703\">dotnet\/runtime #50703<\/a> &#8212; Do not confuse fgDispBasicBlocks in fgMorphBlocks<\/li>\n<\/ul>\n<h3>Dynamic PGO<\/h3>\n<p>The following improvements have been made to support <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/43618\">dynamic PGO<\/a>.<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/51664\">dotnet\/runtime #51664<\/a> &#8212; Update JIT to consume the new &#8220;LikelyClass&#8221; records seen from crossgen-processed PGO data<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50213\">dotnet\/runtime #50213<\/a> &#8212; Tolerate edge profile inconsistencies better<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50633\">dotnet\/runtime #50633<\/a> &#8212; fixes for mixed PGO\/nonPGO compiles<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50765\">dotnet\/runtime #50765<\/a> &#8212; Revise fgExpandRunRarelyBlocks<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/51593\">dotnet\/runtime #51593<\/a> &#8212; Revise inlinee scale computations<\/li>\n<\/ul>\n<h3>JIT Loop Optimizations<\/h3>\n<p>The following improvements have been made for <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/43549\">loop optimizations<\/a>.<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50982\">dotnet\/runtime #50982<\/a> &#8212; Generalize loop inversion<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/51757\">dotnet\/runtime #51757<\/a> &#8212; Don&#8217;t recompute preds lists during loop cloning<\/li>\n<\/ul>\n<h3>LSRA<\/h3>\n<p>The following improvements have been made to <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/main\/docs\/design\/coreclr\/jit\/lsra-detail.md\">Linear Scan Register Allocation (LRSA)<\/a>.<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/51281\">dotnet\/runtime #51281<\/a> &#8212; Improve LRSA stats to include register selection heuristics information<\/li>\n<\/ul>\n<h3>Optimizations<\/h3>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/49930\">dotnet\/runtime #49930<\/a> &#8212; Fold null checks for const strings at the Value Numbering level<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50000\">dotnet\/runtime #50000<\/a> &#8212; Fold null checks against initialized static readonly fields of ref types<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50112\">dotnet\/runtime #50112<\/a> &#8212; Don&#8217;t allocate string literals inside potential BBJ_THROW candidates<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50644\">dotnet\/runtime #50644<\/a> &#8212; Enable CSE for VectorX.Create<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50806\">dotnet\/runtime #50806<\/a> &#8212; Give up on the tail call if there are unexpected blocks after it<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/50832\">dotnet\/runtime #50832<\/a> &#8212; Updating <code>Vector&lt;T&gt;<\/code> to support <code>nint<\/code> and nuint<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/runtime\/pull\/51409\">dotnet\/runtime #51409<\/a> &#8212; Generalize the branch around empty flow optimization<\/li>\n<\/ul>\n<h2>.NET Diagnostics: EventPipe for Mono and Improved EventPipe Performance<\/h2>\n<p>EventPipe is .NET&#8217;s cross-platform mechanism for egressing events, performance data, and counters. Starting with .NET 6, we&#8217;ve moved the implementation from C++ to C. With this change, Mono will be able to use EventPipe as well! This means that both CoreCLR and Mono will use the same eventing infrastructure, including the .NET Diagnostics CLI Tools! This change also came with small reduction in size for CoreCLR:<\/p>\n<table>\n<thead>\n<tr>\n<th>lib<\/th>\n<th>after size &#8211; before size<\/th>\n<th>diff<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>libcoreclr.so<\/td>\n<td>7037856 &#8211; 7049408<\/td>\n<td>-11552<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We&#8217;ve also made some changes that improve EventPipe throughput while under load. Over the first few previews, we&#8217;ve made a series of changes that result in throughput improvements as high as 2.06x what .NET 5 was capable of:\n<img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/20667293\/119393587-00cce680-bc86-11eb-87a0-2d6b9a575f84.png\" alt=\"image\" \/><\/p>\n<blockquote><p>Data collected using the EventPipeStress framework in dotnet\/diagnostics. The writer app writes events as fast as it can for 60 seconds. The number of successful and dropped events is recorded.<\/p><\/blockquote>\n<p>For more information, see <a href=\"https:\/\/github.com\/dotnet\/runtime\/issues\/45518\">dotnet\/runtime #45518<\/a>.<\/p>\n<h2>IL trimming<\/h2>\n<h3>Warnings enabled by default<\/h3>\n<p>Trim warnings tell you about places where trimming may remove code that&#8217;s used at runtime. These warnings were previously disabled by default because the warnings were very noisy, largely due to the .NET platform not participating in trimming as a first class scenario.<\/p>\n<p>We&#8217;ve annotated large portions of the .NET libraries (the runtime libraries, not ASP.NET Core or Windows Desktop frameworks) so that they produce accurate trim warnings. As a result, we felt it was time to enable trimming warnings by default.<\/p>\n<p>You can disable warnings by setting <code>&lt;SuppressTrimAnalysisWarnings&gt;<\/code> to <code>true<\/code>. With earlier releases, you can set the same property to <code>false<\/code> to see the trim warnings.<\/p>\n<p>Trim warnings bring predictability to the trimming process and put power in developers&#8217; hands. We will continue annotating more of the .NET libraries, including ASP.NET Core in subsequent releases. We hope the community will also improve the trimming ecosystem by annotating more code to be trim safe.<\/p>\n<p>More information:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/mono\/linker\/blob\/main\/docs\/fixing-warnings.md\">Trim warnings in .NET 6<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/dotnet\/core\/deploying\/prepare-libraries-for-trimming\">Prepare .NET libraries for trimming<\/a><\/li>\n<\/ul>\n<h3>Default TrimMode=link<\/h3>\n<p>The new default Trim Mode in .NET 6 is <code>link<\/code>. The <code>link<\/code> TrimMode can provide significant savings by trimming not just unused assemblies, but also unused members.<\/p>\n<p>In .NET 5, trimming tried to find and remove unreferenced assemblies by default. This is safer, but provides limited benefit. Now that trim warnings are on by default developers can be confident in the results of trimming.<\/p>\n<p>Let&#8217;s take a look at this trimming improvement by trimming one of the .NET SDK tools, as an example. I&#8217;m going to use <a href=\"https:\/\/docs.microsoft.com\/dotnet\/core\/deploying\/ready-to-run\">crossgen, the Ready To Run compiler<\/a>. It can be trimmed with only a few trim warnings, which the crossgen team was able to resolve.<\/p>\n<p>First, let&#8217;s look at publishing crossgen as a self-contained app without trimming. It is 80 MB (which includes the .NET runtime and all the libraries).<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/515774\/115949313-18e3f700-a489-11eb-8f2d-55aad4950bea.png\" alt=\"image\" \/><\/p>\n<p>We can then try out the (now legacy) .NET 5 default trim mode, <code>copyused<\/code>. The result drops to 55 MB.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/515774\/115949175-01583e80-a488-11eb-9b2d-370e89aa1bdb.png\" alt=\"image\" \/><\/p>\n<p>The new .NET 6 default trim mode,<code>link<\/code>, drops the self-contained file size much further, to 36MB.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/515774\/115949349-652f3700-a489-11eb-83af-a5849c0c54bf.png\" alt=\"image\" \/><\/p>\n<p>We hope that the new <code>link<\/code> trim mode aligns much better with the expectations for trimming: significant savings and predictable results.<\/p>\n<h3>Shared model with Native AOT<\/h3>\n<p>We&#8217;ve implemented the same trimming warnings for the <a href=\"https:\/\/github.com\/dotnet\/runtimelab\/issues\/248\">Native AOT experiment<\/a> as well, which should improve the Native AOT compilation experience in much the same way.<\/p>\n<h2>Single-file publishing<\/h2>\n<p>The following improvements have been made for single-file application publishing.<\/p>\n<h3>Static Analysis<\/h3>\n<p>Analyzers for single-file publishing were added in .NET 5 to warn about <code>Assembly.Location<\/code> and a few other APIs which behave differently in single-file bundles.<\/p>\n<p>For .NET 6 Preview 4 we&#8217;ve improved the analysis to allow for custom warnings. If you have an API which doesn&#8217;t work in single-file publishing you can now mark it with the <code>[RequiresAssemblyFiles]<\/code> attribute, and a warning will appear if the analyzer is enabled. Adding that attribute will also silence all warnings related to single-file in the method, so you can use the warning to propagate warnings upward to your public API.<\/p>\n<p>The analyzer is automatically enabled for exe projects when <code>PublishSingleFile<\/code> is set to <code>true<\/code>, but you can also enabled it for any project by setting <code>EnableSingleFileAnalysis<\/code> to <code>true<\/code>. This is could be helpful if you want to embed a library in a single file bundle.<\/p>\n<h3>Compression<\/h3>\n<p>Single-file bundles now support compression, which can be enabled by setting the property <code>EnableCompressionInSingleFile<\/code> to <code>true<\/code>. At runtime, files are decompressed to memory as necessary. Compression can provide huge space savings for some scenarios.<\/p>\n<p>Let&#8217;s look at single file publishing, with and without compression, used with <a href=\"https:\/\/github.com\/NuGetPackageExplorer\/NuGetPackageExplorer\">NuGet Package Explorer<\/a>.<\/p>\n<p>Without compression: 172 MB<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/515774\/115341581-b96eaa00-a15d-11eb-8ec2-a6739caa6da5.png\" alt=\"image\" \/><\/p>\n<p>With compression: 71.6 MB<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/user-images.githubusercontent.com\/515774\/115341896-39950f80-a15e-11eb-94fe-9e4c7c77118d.png\" alt=\"image\" \/><\/p>\n<p>Compression can significantly increase the startup time of the application, especially on Unix platforms (because they have a no-copy fast start path that can&#8217;t be used with compression). You should test your app after enabling compression to see if the additional startup cost is acceptable.<\/p>\n<h2><code>PublishReadyToRun<\/code> now uses crossgen2 by default<\/h2>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/conversation-about-crossgen2\/\">Crossgen2<\/a> is now enabled by default when publishing ReadyToRun images. It also optionally supports generating composite images.<\/p>\n<p>The following setting are exposed to enable you to configure publishing with ready to run code. The settings are set to their default values.<\/p>\n<pre><code class=\"language-xml\">    &lt;PublishReadyToRun&gt;false&lt;\/PublishReadyToRun&gt;\r\n    &lt;!-- set to true to enable publishing with ready to run native code --&gt;\r\n    &lt;PublishReadyToRunUseCrossgen2&gt;true&lt;\/PublishReadyToRunUseCrossgen2&gt; \r\n    &lt;!-- set to false to use crossgen like in 5.0 --&gt;\r\n    &lt;PublishReadyToRunComposite&gt;false&lt;\/PublishReadyToRunComposite&gt;\r\n    &lt;!-- set to true to generate a composite R2R image --&gt;<\/code><\/pre>\n<h2>CLI install of .NET 6 SDK Optional Workloads<\/h2>\n<p>.NET 6 will introduce the concept of <a href=\"https:\/\/github.com\/dotnet\/designs\/blob\/main\/accepted\/2020\/workloads\/workloads.md\">SDK workloads<\/a> that can be install after the fact on top of the .NET SDK to enable various scenarios. The new workloads available in preview 4 are .NET MAUI and Blazor WebAssembly AOT workloads.<\/p>\n<p>For the .NET MAUI workloads, we still recommend using the <a href=\"https:\/\/github.com\/Redth\/dotnet-maui-check\">maui-check<\/a> tool for preview 4 as it includes additional components not yet available in Visual Studio or as an .NET SDK workload. To try out the .NET SDK experience anyway (using iOS as the example), run <code>dotnet workload install microsoft-ios-sdk-full<\/code>. Once installed, you can run <code>dotnet new ios<\/code> and then <code>dotnet build<\/code> to create and build your project.<\/p>\n<p>For Blazor WebAssembly AOT, follow the <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/asp-net-core-updates-in-net-6-preview-4\/\">installation instructions<\/a> provided via the ASP.NET blog.<\/p>\n<p>Preview 4 includes .NET MAUI workloads for iOS, Android, tvOS, MacOS, and MacCatalyst.<\/p>\n<p>Note that <code>dotnet workload install<\/code> copies the workloads from NuGet.org into your SDK install so will need to be run elevated\/sudo if the SDK install location is protected (meaning at an admin\/root location).<\/p>\n<h2>Built-in SDK version checking<\/h2>\n<p>To make it easier to track when new versions of the SDK and Runtimes are available, we\u2019ve added a new command to the .NET 6 SDK: <code>dotnet sdk check<\/code><\/p>\n<p>This will tell you within each feature band what is the latest available version of the .NET SDK and .NET Runtime.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/user-images.githubusercontent.com\/12663534\/119046999-374aee80-b972-11eb-8967-2111b7e7a586.png\" alt=\"sdkcheck\" width=\"339\" height=\"218\" \/><\/p>\n<h2>CLI Templates (<code>dotnet new<\/code>)<\/h2>\n<p>Preview 4 introduces a new search capability for templates. <code>dotnet new --search<\/code> will search <a href=\"https:\/\/www.nuget.org\/\">NuGet.org<\/a> for matching templates. During upcoming previews the data used for this search will be updated more frequently.<\/p>\n<p>Templates installed in the CLI are available for both the CLI and Visual Studio. An earlier problem with user installed templates being lost when a new version of the SDK was installed has been resolved, however templates installed prior to .NET 6 Preview 4 will need to be reinstalled.<\/p>\n<p>Other improvements to template installation include support for the <code>--interactive<\/code> switch to support authorization credentials for private NuGet feeds.<\/p>\n<p>Once CLI templates are installed, you can check if updates are available via <code>--update-check<\/code> and <code>--update-apply<\/code>. This will now reflect template updates much more quickly, support the NuGet feeds you have defined, and support <code>--interactive<\/code> for authorization credentials.<\/p>\n<p>In Preview 4 and upcoming Previews, the output of <code>dotnet new<\/code> commands will be cleaned up to focus on the information you need most. For example, the <code>dotnet new --install &lt;package&gt;<\/code> lists only the templates just installed, rather than all templates.<\/p>\n<p>To support these and upcoming changes to <code>dotnet new<\/code>, we are making significant changes to the Template Engine API that may affect anyone hosting the template engine. These changes will appear in Preview 4 and Preview 5. If you are hosting the template engine, please connect with us at https:\/\/github.com\/dotnet\/templating so we can work with you to avoid or minimize disruption.<\/p>\n<h2>Support<\/h2>\n<p>.NET 6 will be will be released in November 2021, and will be supported for three years, as a <a href=\"https:\/\/github.com\/dotnet\/core\/blob\/master\/release-policies.md\">Long Term Support (LTS) release<\/a>. The <a href=\"https:\/\/github.com\/dotnet\/core\/blob\/master\/release-notes\/6.0\/supported-os.md\">platform matrix<\/a> has been significantly expanded.<\/p>\n<p>The additions are:<\/p>\n<ul>\n<li>Android.<\/li>\n<li>iOS.<\/li>\n<li>Mac and Mac Catalyst, for x64 and Apple Silicon (AKA &#8220;M1&#8221;).<\/li>\n<li>Windows Arm64 (specifically Windows Desktop).<\/li>\n<\/ul>\n<p>.NET 6 Debian container images are based on Debian 11 (&#8220;bullseye&#8221;), which is <a href=\"https:\/\/wiki.debian.org\/DebianBullseye\">currently in testing<\/a>.<\/p>\n<h2>Closing<\/h2>\n<p>We&#8217;re well into the .NET 6 release at this point. While the final release in November still seems like a long way off, we&#8217;re getting close to being done feature development. Now is a great time for feedback since the shape of the new features are now established and we&#8217;re still in the active development phase so can readily act on that feedback.<\/p>\n<p>Speaking of November, please book off some time during November 9-11 to watch <a href=\"https:\/\/www.dotnetconf.net\/\">.NET Conf 2021<\/a>. It is certain to be exciting and fun. We&#8217;ll be releasing the final .NET 6 build on November 9th, and a blog post even longer than this one.<\/p>\n<p>Still looking for more to read? You might check out our new <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/category\/conversations\/\">conversations<\/a> series. There is a lot of detailed insights about new .NET 6 features.<\/p>\n<p>We hope you enjoy trying out preview 4.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>.NET 6 Preview 4 is now available.<\/p>\n","protected":false},"author":1312,"featured_media":21638,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,196],"tags":[],"class_list":["post-33036","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-dotnet-core"],"acf":[],"blog_post_summary":"<p>.NET 6 Preview 4 is now available.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/33036","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\/1312"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=33036"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/33036\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21638"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=33036"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=33036"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=33036"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}