# Announcing .NET 5.0/发布

We’re excited to release .NET 5.0 today and for you to start using it. It’s a major release — including C# 9 and F# 5 — with a broad set of new features and compelling improvements. It’s already in active use by teams at Microsoft and other companies, in production and for performance testing. Those teams are showing us great results that demonstrate performance gains and/or opportunities to reduce hosting costs for their web applications. We’ve been running our own website on 5.0 since Preview 1. From what we’ve seen and heard so far, .NET 5.0 delivers significant value without much effort to upgrade. It’s a great choice for your next app, and a straightforward upgrade from earlier .NET Core versions. We hope you enjoy using it, on your desktop, laptop, and cloud instances.

ASP.NET Core, EF Core, C# 9, and F# 5 are also being released today. .NET Conf 2020 — our free and virtual conference — is being held today so you can learn about all of the new releases.

You can download .NET 5.0, for Windows, macOS, and Linux, for x86, x64, Arm32, Arm64.

ASP.NETCore、EF Core、C#9和F#5也将于今天发布。今天我们的虚拟会议是免费的，你可以了解我们的所有会议。

Installers and binaries

Container images

Linux packages

Release notes

Known issues

GitHub issue tracker

.NET 5.0 Contributors

For Visual Studio users, you need Visual Studio 16.8 or later to use .NET 5.0 on Windows and the latest version of Visual Studio for Mac) on macOS. The C# extension for Visual Studio Code already supports .NET 5.0 and C# 9.

.NET 5.0 is the first release in our .NET unification journey. We built .NET 5.0 to enable a much larger group of developers to migrate their .NET Framework code and apps to .NET 5.0. We’ve also done much of the early work in 5.0 so that Xamarin developers can use the unified .NET platform when we release .NET 6.0. There is more on .NET unification, later in the post.

.NET5.0是我们的.NET统一之旅中的第一个版本。我们构建.NET5.0是为了让更多的开发人员能够将他们的.NETFramework代码和应用程序迁移到.NET5.0。我们还在5.0中做了很多前期工作，以便Xamarin开发人员在发布.NET6.0时可以使用统一的.NET平台。在后面的帖子中，有更多关于.NET的统一。

Now is a good time to call out the incredible collaboration with everyone contributing to the .NET project. This release marks the fifth major .NET version as an open source project. There is now a large mix of individuals and small and large companies (including the .NET Foundation corporate sponsors) working together as a large community on various aspects of .NET in the dotnet org on GitHub. The improvements in .NET 5.0 are the result of many people, their effort, smart ideas, and their care and love for the platform, all above and beyond Microsoft’s stewardship of the project. From the core team working on .NET every day, we extend a very large “thank you” to everyone that contributed to .NET 5.0 (and previous releases)!

We introduced .NET 5.0 way back in May 2019, and even set the November 2020 release date at that time. From that post: “we will ship .NET Core 3.0 this September, .NET 5 in November 2020, and then we intend to ship a major version of .NET once a year, every November”. You’d think that “November 2020” was a cheque that could not be cashed given all the challenges this year, however, .NET 5.0 has been released on time. Thanks to everyone on the team that made that happen! I know it has not been easy. Looking forward, you should expect .NET 6.0 in November 2021. We intend to release new .NET versions every November.

The rest of the blog is dedicated to highlighting and detailing most of the improvements in .NET 5.0. There is also an update on our .NET unification vision.

.NET 5.0 Highlights/.NET 5.0亮点
There are many important improvements in .NET 5.0:

.NET 5.0中有许多重要的改进：

.NET 5.0 is already battle-tested by being hosted for months at dot.net and Bing.com (version).

Performance is greatly improved across many components and is described in detail at Performance Improvements in .NET 5.0, Arm64 Performance in .NET 5.0, and gRPC.

C# 9 and F# 5 offer new language improvements such as top-level programs and records for C# 9, while F# 5 offers interactive programming and a performance boost for functional programming on .NET.

.NET libraries have enhanced performance for Json serialization, regular expressions, and HTTP (HTTP 1.1, HTTP/2). They are also are now completely annotated for nullability.

P95 latency has dropped due to refinements in the GC, tiered compilation, and other areas.

Application deployment options are better, with ClickOnce client app publishing, single-file apps, reduced container image size, and the addition of Server Core container images.

Platform scope expanded with Windows Arm64 and WebAssembly.

.NET5.0已经在进行了几个月的战斗测试点.net以及必应（版本）。

C#9和F#5提供了新的语言改进，例如C#9的顶级程序和记录，而F#5提供了交互式编程和.NET函数式编程的性能提升。

.NET库增强了Json序列化、正则表达式和HTTP（HTTP 1.1、HTTP/2）的性能。它们现在也完全被注释为空。

I’ve written many samples for the .NET 5.0 preview posts. You might want to take a look at .NET 5.0 Examples to learn more about new C# 9 and libraries features.

Platform and Microsoft Support/平台和Microsoft支持
.NET 5.0 has a nearly identical platform support matrix as .NET Core 3.1, for Windows, macOS, and Linux. If you are using .NET Core 3.1 on a supported operating system, you should be able to adopt .NET 5.0 on that same operating system version for the most part. The most significant addition for .NET 5.0 is Windows Arm64.

.NET5.0与.NETCore3.1（适用于Windows、macOS和Linux）具有几乎相同的平台支持矩阵。如果您在受支持的操作系统上使用.NETCore3.1，那么在大多数情况下，您应该能够在相同的操作系统版本上采用.NET5.0。对于ARMNET来说，64.0.0是最重要的附加功能。

.NET 5.0 is a current release. That means that it will be supported for three months after .NET 6.0 is released. As a result, we expect to support .NET 5.0 through the middle of February 2022. .NET 6.0 will be an LTS release and will be supported for three years, just like .NET Core 3.1.

.NET5.0是当前版本。这意味着它将在.NET6.0发布后的三个月内得到支持。因此，我们希望在2022年2月中旬支持.NET5.0。NET6.0将是一个LTS版本，它将支持三年，就像.NETCore3.1一样。

Unified platform vision/统一平台愿景
Last year, we shared a vision of a unified .NET stack and ecosystem. The value to you is that you will be able to use a single set of APIs, languages, and tools to target a broad set of application types, including mobile, cloud, desktop, and IoT. You might realize that you can already target a broad set of platforms with .NET today, however, the tools and APIs are not always the same across Web and Mobile, for example, or released at the same time.

As part of .NET 5.0 and 6.0, we are unifying .NET into a single product experience, while enabling you to pick just the parts of the .NET platform that you want to use. If you want to target Mobile and not WebAssembly, you don’t need to download the WebAssembly tools, and vice versa. Same with ASP.NET Core and WPF. You’ll also have a much easier way to acquire all the .NET tools and build and runtime packs that you need from the command line. We’re enabling a package manager experience (including using existing package managers) for .NET platform components. That will be great for many scenarios. Quick construction of a development environment and CI/CD will probably be the biggest beneficiaries.

We had intended to deliver the entirety of the unification vision with .NET 5.0, but in the wake of the global pandemic, we had to adapt to the changing needs of our customers. We’ve been working with teams from companies from around the world that have needed help to speed up their adoption of cloud technologies. They, too, have had adapt to the changing needs of their customers. As a result, we are delivering the vision across two releases.

The first step towards this vision was consolidating .NET repos, including a large subset of Mono. Having one repo for the runtime and libraries for .NET is a precondition to delivering the same product everywhere. It also helps with making broad changes that affect runtime and libraries, where there were previously repo boundaries. Some people were worried that a large repo would be harder to manage. That hasn’t proven to be the case.

In the .NET 5.0 release, Blazor is best example of taking advantage of repo consolidation and .NET unification. The runtime and libraries for Blazor WebAssembly are now built from the consolidated dotnet/runtime repo. That means Blazor WebAssembly and Blazor on the server use the exact same code for List, for example. That wasn’t the case for Blazor prior to .NET 5.0. The approach we took for Blazor WebAssembly is very similar to what we’ll do with Xamarin in .NET 6.0.

The .NET Framework remains a supported Microsoft product and will continue to be supported with each new version of Windows. We announced last year that we had stopped adding new features to .NET

.NET Framework仍然是受支持的Microsoft产品，并且将继续受Windows的每个新版本的支持。我们去年宣布停止向.NET添加新功能

Framework and finished adding .NET Framework APIs to .NET Core. That means that now is a great time to consider moving your .NET Framework apps to .NET Core. For .NET Framework client developers, Windows Forms and WPF are supported with .NET 5.0. We’ve heard from many developers that porting from .NET Framework is straightforward. For .NET Framework server developers, you need to adopt ASP.NET Core to use .NET 5.0. For Web Forms developers, we believe that Blazor provides a similar developer experience with an efficient and much more modern implementation. WCF server and Workflow users can look to community projects that are supporting those frameworks. The porting from .NET Framework to .NET Core doc is a good place to start. That all said, keeping your app on .NET Framework is a fine approach if you are happy with your experience.

The Windows team is working on Project Reunion as the next step forward for UWP and related technologies. We’ve been collaborating with the Reunion team to ensure that .NET 5.0 and later versions will work well with WinUI and WebView2. The Project Reunion repo is the best place to stay up to date with progress.

Windows团队正致力于Reunion项目，作为UWP和相关技术的下一步。我们一直在与Reunion团队合作，以确保.NET5.0及更高版本能够与WinUI和WebView2一起工作。项目留尼汪回购是保持最新进展的最佳场所。

Let’s switch to looking at what’s new in the 5.0 release.

Languages/语言文字
C# 9 and F# 5 are part of the .NET 5.0 release and included in the .NET 5.0 SDK. Visual Basic is also included in the 5.0 SDK. It does not include language changes, but has improvements to support the Visual Basic Application Framework on .NET Core.

C#9和F#5是.NET5.0版本的一部分，包含在.NET5.0SDK中。visualbasic也包含在5.0sdk中。它不包括语言更改，但有一些改进以支持.NETCore上的VisualBasic应用程序框架。

C# Source Generators are an important new C# compiler feature. They are not technically part of C# 9 since it doesn’t have any language syntax. See New C# Source Generator Samples to help you get started using this new feature. We expect to make more use of source generators within the .NET product in .NET 6.0 and beyond.

C源代码生成器是一个重要的新的C编译器特性。从技术上讲，它们不是C#9的一部分，因为它没有任何语言语法。请参阅新的C源代码生成器示例，以帮助您开始使用此新功能。我们希望在.NET6.0及更高版本的.NET产品中更多地使用源生成器。

As a way to try out the new release ourselves, a few of us decided to update the dotnet/iot repo to use new C# 9 syntax and target .NET 5.0. The changes resulted in removing >2k lines of code, just by adopting new syntax. It uses top-level programs, records, patterns, and switch expressions. It has also been updated to take advantage of the complete set of nullable annotations in .NET libraries. We also updated the .NET IoT docs. We’ll take a look at few examples from that repo to explore C# 9.

Top-level programs/顶级课程
The led-blink program is a nice compact top-level program example.

led闪烁程序是一个很好的紧凑的顶级程序示例。

using System;using System.Device.Gpio;using System.Threading;var pin = 18;var lightTime = 1000;var dimTime = 200;Console.WriteLine( " L e t ′ s b l i n k a n L E D ! " ) ; u s i n g G p i o C o n t r o l l e r c o n t r o l l e r = n e w ( ) ; c o n t r o l l e r . O p e n P i n ( p i n , P i n M o d e . O u t p u t ) ; C o n s o l e . W r i t e L i n e ( "Let's blink an LED!");using GpioController controller = new (); controller.OpenPin(pin, PinMode.Output);Console.WriteLine( “GPIO pin enabled for use: {pin}”);// turn LED on and offwhile (true){
Console.WriteLine($“Light for {lightTime}ms”); controller.Write(pin, PinValue.High); Thread.Sleep(lightTime); Console.WriteLine($"Dim for {dimTime}ms");
controller.Write(pin, PinValue.Low);


You can also see the use of target-typed new, with the assignment to the controller variable. The GpioController type is only defined on the left-hand side of the assignment. The type is inferred on the right-hand side. This new syntax is an alternative to var, which has the type only showing on the right-hand side of the assignment and is inferred on the left-hand side with the var keyword.

Top-level programs can also grow in complexity, by defining methods and taking advantage of types defined in the same or other files. The CharacterLcd sample demonstrates some of those capabilities.

Logical and property patterns/逻辑和属性模式
C# 9 includes support for new patterns. You can see an example of a logical pattern in the following code from the CCS811 Gas sensor.

C#9包括对新模式的支持。您可以在以下代码中看到CCS811气体传感器的逻辑模式示例。

var threshChoice = Console.ReadKey();Console.WriteLine();if (threshChoice.KeyChar is ‘Y’ or ‘y’){
TestThresholdAndInterrupt(ccs811);}
Another new pattern is property patterns. You can see several properties checks in my Mycroft information access 6.0 sample. The following code is taken from the PN532 RFID and NFC reader sample.

if (pollingType is null or { Length: >15 }){
return null;}
This code tests if pollingType (which is typed as byte[]?) is null or contains >15 bytes.

I want to show you two more patterns. The first is a logical pattern in Mcp25xxx CAN bus.

_ => throw new ArgumentException(nameof(address), $“Invalid address value {address}.”),}; The second is a logical pattern in Piezo Buzzer Controller. 第二种是压电式蜂鸣器控制器的逻辑模式。 if (element is not NoteElement noteElement){ // In case it’s a pause element we have only just wait desired time. Thread.Sleep(durationInMilliseconds);}else{ // In case it’s a note element we play it. var frequency = GetFrequency(noteElement.Note, noteElement.Octave); _buzzer.PlayTone(frequency, (int)(durationInMilliseconds * 0.7)); Thread.Sleep((int)(durationInMilliseconds * 0.3));} Records/记录 C# 9 includes a new type of class called a record. It has a number of benefits compared to regular classes, half of which relate to more terse syntax. The following record is taken from the Bh1745 RGB Sensor binding. C#9包含一种新的类，称为记录。与常规类相比，它有许多优点，其中一半与更简洁的语法有关。以下记录取自Bh1745 RGB传感器绑定。 public record ChannelCompensationMultipliers(double Red, double Green, double Blue, double Clear); It is then used a little later in the same file, with familiar syntax: 稍后在同一个文件中使用它，使用熟悉的语法： ChannelCompensationMultipliers = new (2.2, 1.0, 1.8, 10.0); Nullability annotation improvements/可空性注释改进 The .NET libraries are now completely annotated for nullability. That means if you enable nullability, you’ll get more type information from the platform to direct your use of the feature. At present, the .NET docs have not been fully annotated. For example, String.IsNullOrEmpty(string) should be annotated to take a string?, while String.Split(Char[]) has an annotation of char[]?. We hope that will get fixed soon. Complete information is available at source.dot.net and via F12 metadata lookups in Visual Studio. NET库现在已经完全注释为空。这意味着，如果您启用了nullability，您将从平台获得更多类型信息，以指导您使用该特性。目前，.NET文档尚未完全注释。例如，String.IsNullOrEmpty（string）应该加注释以获取字符串？，同时字符串。拆分（Char[]）的注释为Char[]？。我们希望很快就能修好。完整信息请访问源.dot.net通过Visual Studio F12查找元数据。 The System.Device.Gpio and Iot.Device.Bindings packages (version 1.1.0 for both) have also been annotated as part of this release, using the updated .NET 5.0 annotations. Those libraries are both multi-targeted, however, we use the 5.0 view to produce annotations for all targets. 这个系统设备.Gpio以及物联网设备绑定包（版本1.1.0）也在这个版本中使用更新的.NET5.0注释进行了注释。这些库都是多目标的，但是，我们使用5.0视图为所有目标生成注释。 Note: Existing .NET Core 3.1 code might generate new diagnostics (if you have nullability enabled) when you retarget it to .NET 5.0, since there are new annotations. 注意：当您将现有的.NETCore3.1代码重新定位到.NET5.0时，它可能会生成新的诊断（如果您启用了空性），因为有新的注释。 We’ve also added new annotation types. It’s common for large classes to instantiate object members in helper methods called from a constructor. The C# compiler can’t follow the flow of calls to the object assignment. It will think that the member is null when exiting the constructor and will warn with CS8618. The MemberNotNull attribute resolves this problem. You apply the attribute to the helper method. The compiler will then see that you set this value and realize that the method is called from a constructor. MemberNotNullWhen is similar. 我们还添加了新的注释类型。大型类在从构造函数调用的helper方法中实例化对象成员是很常见的。C编译器无法跟踪对对象赋值的调用流。当退出构造函数时，它将认为该成员为null，并用CS8618发出警告。MemberNotNull属性解决了这个问题。将属性应用于helper方法。编译器将看到您设置了这个值，并意识到该方法是从构造函数调用的。MemberNotNullWhen类似。 You can see an example of MemberNotNull in the BMxx80 temperature sensors with the following code. 您可以在BMxx80温度传感器中看到MemberNotNull的示例，代码如下。 [MemberNotNull(nameof(_calibrationData))]private void ReadCalibrationData(){ switch (this) { case Bme280 _: _calibrationData = new Bme280CalibrationData(); _controlRegister = (byte)Bmx280Register.CTRL_MEAS; break; case Bmp280 _: _calibrationData = new Bmp280CalibrationData(); _controlRegister = (byte)Bmx280Register.CTRL_MEAS; break; case Bme680 _: _calibrationData = new Bme680CalibrationData(); _controlRegister = (byte)Bme680Register.CTRL_MEAS; break; default: throw new Exception(“Bmxx80 device not correctly configured. Could not find calibraton data.”); } _calibrationData.ReadFromDevice(this);} The actual code uses conditional compilation. That’s because the project is multi-targeted, and this attribute is only supported with .NET 5.0+ . The use of the attribute enables skipping runtime checks (in the constructor) that would otherwise be needed to satisfy nullability requirements, as is the case for earlier .NET versions. 实际代码使用条件编译。这是因为该项目是多目标的，并且只有.NET5.0+才支持此属性。使用该属性可以跳过运行时检查（在构造函数中），否则将需要这些检查来满足可空性要求，就像早期的.NET版本一样。 Tools/工具 We’ve improved the Windows Forms designer, changed the way that target frameworks work for .NET 5.0 and beyond, changed the way that WinRT is supported, and made other improvements. 我们改进了Windows窗体设计器，改变了目标框架在.net5.0及更高版本上的工作方式，改变了WinRT的支持方式，并进行了其他改进。 Windows Forms designer/Windows窗体设计器 The Windows Forms designer (for .NET Core 3.1 and .NET 5.0) has been updated in Visual Studio 16.8, and now supports all Windows Forms controls. It also supports the Telerik UI for WinForms controls. The designer includes all the designer functionality you would expect, including: drag-and-drop, selection, move and resize, cut/copy/paste/delete of controls, integration with the Properties Window, events generation and more. Data binding and support for a broader set of third party controls is coming soon. Windows窗体设计器（用于.NET Core 3.1和.NET 5.0）已在Visual Studio 16.8中更新，现在支持所有Windows窗体控件。它还支持WinForms控件的Telerik用户界面。设计器包含您所期望的所有设计器功能，包括：拖放、选择、移动和调整大小、剪切/复制/粘贴/删除控件、与属性窗口集成、事件生成等。数据绑定和对更广泛的第三方控制的支持即将到来。 Learn more in the Windows Forms Designer for .NET Core Released post. 有关详细信息，请参阅Windows窗体设计器for.NET Core发布的文章。 .NET 5.0 Target Framework/.NET 5.0目标框架 We have changed the approach we use for target frameworks with .NET 5.0. The following project file demonstrate the new .NET 5.0 target framework. 我们已经改变了使用.NET5.0的目标框架的方法。下面的项目文件演示了新的.NET5.0目标框架。 Exe net5.0 The new net5.0 form is more compact and intuitive than the netcoreapp3.1 style we’ve used until this point. In addition, we are extending the target framework to describe operating system dependencies. This change is motivated by our vision to enable targeting iOS and Android with Xamarin in .NET 6.0. 新的net5.0表单比我们在此之前使用的netcoreapp3.1样式更加简洁和直观。此外，我们正在扩展目标框架来描述操作系统依赖性。这一变化的动机是我们的愿景，即在.NET6.0中使用Xamarin实现iOS和Android的目标。 Windows desktop APIs (including Windows Forms, WPF, and WinRT) will only be available when targeting net5.0-windows. You can specify an operating system version, like net5.0-windows7 or net5.0-windows10.0.17763.0 ( for Windows October 2018 Update). You need to target a Windows 10 version if you want to use WinRT APIs. Windows桌面API（包括Windows窗体、WPF和WinRT）仅在针对net5.0-Windows时可用。您可以指定操作系统版本，如net5.0-windows7或net5.0-windows10.0.17763.0（对于Windows 2018年10月更新）。如果您需要使用WinRT API版本，则需要使用WinRT API。 Cross-platform scenarios can be a bit more challenging, when using the new net5.0-windows TFM. System.Device.Gpio demonstrates a pattern for managing the Windows target-framework if you want to avoid building for Windows or avoid pulling Windows runtime packages on Linux, for example. 当使用新的net5.0-windows TFM时，跨平台场景可能会更具挑战性。系统设备.Gpio举例来说，如果您希望避免为Windows构建或避免在Linux上拉取Windows运行时包，则演示一种管理Windows目标框架的模式。 Summary of changes: net5.0 is the new Target Framework Moniker (TFM) for .NET 5.0. net5.0 combines and replaces netcoreapp and netstandard TFMs. net5.0 supports .NET Framework compatibility mode net5.0-windows will be used to expose Windows-specific functionality, including Windows Forms, WPF and WinRT APIs. .NET 6.0 will use the same approach, with net6.0, and will add net6.0-ios and net6.0-android. The OS-specific TFMs can include OS version numbers, like net6.0-ios14. Portable APIs, like ASP.NET Core will be usable with net5.0. The same will be true of Xamarin forms with net6.0. 变更摘要： net5.0是.net5.0的新目标框架名字对象（TFM）。 net5.0结合并取代了netcoreapp和netstandard TFMs。 net5.0支持.NET Framework兼容模式 net5.0-windows将用于公开特定于windows的功能，包括windows窗体、WPF和winrtapi。 .net6.0将使用与net6.0相同的方法，并将添加net6.0-ios和net6.0-android。 特定于操作系统的tfm可以包括操作系统版本号，如net6.0-ios14。 可移植的API，比如ASP.NET内核将可用于net5.0。对于net6.0的Xamarin表单也是如此。 The templates in Visual Studio 16.8 still target .NET Core 3.1, for console, WPF and Windows Forms apps. The ASP.NET templates have been updated to support .NET 5.0. We will update the templates in Visual Studio 16.9 for the remaining templates. VisualStudio16.8中的模板仍然针对.NETCore3.1，用于控制台、WPF和Windows窗体应用程序。这个ASP.NET模板已更新为支持.NET5.0。我们将更新visualstudio16.9中剩余模板的模板。 WinRT Interop (Breaking Change)/WinRT Interop（中断更改） On the topic of targeting Windows APIs, we have moved to a new model for supporting WinRT APIs as part of .NET 5.0. This includes calling APIs (in either direction; CLR <==> WinRT), marshaling of data between the two type systems, and unification of types that are intended to be treated the same across the type system or ABI boundary (i.e. “projected types”; IEnumerable and IIterable are examples). 关于面向WindowsAPI的主题，我们已经转向了一种新的模型，它支持WinRT API作为.NET5.0的一部分。这包括调用api（在任何方向；CLR<=>WinRT），在两个类型系统之间封送数据，以及在类型系统或ABI边界上统一处理相同的类型（即“投影类型”；IEnumerable和IIterable都是示例）。 The existing WinRT interop system has been removed from the .NET runtime as part of .NET 5.0. This is a breaking change. That means that apps and libraries using WinRT with .NET Core 3.x will need to be rebuilt and will not run on .NET 5.0 as-is. Libraries that use WinRT APIs will need to multi-target to manage this difference between .NET Core 3.1 and .NET 5.0. 现有的WinRT互操作系统已作为.NET 5.0的一部分从.NET运行时中删除。这是一个突破性的变化。这意味着需要重新构建使用WinRT和.NETCore3.x的应用程序和库，而不能像现在这样在.NET5.0上运行。使用WinRT API的库需要多目标来管理.NETCore3.1和.NET5.0之间的差异。 Going forward, we will rely on the new CsWinRT tool provided by the WinRT team in Windows. It generates C#-based WinRT interop assemblies, which can be delivered via NuGet. That’s exactly what the Windows team is doing, for the WinRT APIs in Windows. The tool can be used by anyone that wants to use WinRT (on Windows) as an interop system, to expose native APIs to .NET or .NET APIs to native code. 接下来，我们将依赖于Windows中WinRT团队提供的新CsWinRT工具。它生成基于C的WinRT互操作程序集，这些程序集可以通过NuGet交付。这正是Windows团队正在做的，对于Windows中的winrtapi。任何人都可以使用该工具来使用WinRT（在Windows上）作为互操作系统，将本机api公开给.NET，或将.netapi公开给本机代码。 The CsWinRT tool is logically similar to tlbimp and tlbexp, although much better. The tlb tools relied on a lot of COM interop plumbing in the .NET runtime. The CsWinRT tool only relies on public .NET APIs. That said, the function pointers feature in C# 9 — and partially implemented in the .NET 5.0 runtime — was in part inspired by the needs of the CsWinRT tool. CsWinRT工具在逻辑上类似于tlbimp和tlbexp，尽管更好。tlb工具在.NET运行时依赖于大量的COM互操作管道。CsWinRT工具只依赖于公共的.netapi。也就是说，C#9中的函数指针特性——部分是在.NET5.0运行时实现的——部分灵感来自CsWinRT工具的需求。 There are several benefits to this new WinRT interop model: It can be developed and improved separate from the .NET runtime. It is symmetrical with the tool-based interop systems provided for other OSes, like iOS and Android. The tool can take advantage of other .NET features (AOT, C# features, IL linking), which was not an option for the previous system. Simplifies the .NET runtime codebase. 这种新的WinRT互操作模型有以下几个优点： 它可以独立于.NET运行时进行开发和改进。 它与为其他操作系统（如iOS和Android）提供的基于工具的互操作系统是对称的。 该工具可以利用其他.NET功能（AOT、C#功能、IL链接），这在以前的系统中不是一个选项。 简化.NET运行时代码库。 You don’t need to add NuGet references to use WinRT APIs. Targeting a Windows 10 TFM — just discussed in the .NET 5.0 TFM section earlier — is enough. If you target .NET Core 3.1 or earlier, you need to reference WinRT packages. You can see this pattern in the System.Device.Gpio project. 不需要添加NuGet引用就可以使用winrtapi。以Windows10TFM为目标—刚才在.NET5.0TFM一节中讨论过—就足够了。如果目标是.NET Core 3.1或更早版本，则需要引用WinRT包。你可以在系统设备.Gpio项目。 Native exports/本地出口 We’ve had requests to enable exports for native binaries that calls into .NET code for a long time. The building block for the scenario is hosting API support for UnmanagedCallersOnlyAttribute. 很长一段时间以来，我们一直在请求为调用.NET代码的本机二进制文件启用导出。该场景的构建块是托管对UnmanagedCallersOnlyAttribute的API支持。 This feature is a building-block for creating higher level experiences. Aaron Robinson, on our team, has been working on a .NET Native Exports project that provides a more complete experience for publishing .NET components as native libraries. We’re looking for feedback on this capability to help decide if the approach should be included in the product. 此功能是创建更高级别体验的构建块。Aaron Robinson在我们的团队中一直致力于一个.NET本机导出项目，该项目为将.NET组件作为本机库发布提供了更完整的体验。我们正在寻找关于此功能的反馈，以帮助决定该方法是否应包含在产品中。 The .NET Native exports project enables you to: Expose custom native exports. Doesn’t require a higher-level interop technology like COM. Works cross-platform. .NET Native exports项目使您能够： 公开自定义本机导出。 不需要更高级别的互操作技术，如COM。 跨平台工作。 There are existing projects that enable similar scenarios, such as: Unmanaged Exports DllExport 现有的项目支持类似的方案，例如： 非托管出口 DLLEX端口 Over the years, we’ve seen a variety of hosting models for .NET in native applications. @rseanhall proposed and implemented a novel new model for doing that, which takes advantage of all the built-in application functionality offered by the .NET application hosting layer (specifically loading dependencies), while enabling a custom entrypoint to be called from native code. That’s perfect for a lot of scenarios, and that one can imagine becoming popular with developers that host .NET components from native applications. That didn’t exist before. Thanks for the contribution, @rseanhall. 多年来，我们在本机应用程序中看到了各种.NET托管模型。@rseanhall为此提出并实现了一个新的模型，该模型利用了.NET应用程序宿主层提供的所有内置应用程序功能（特别是加载依赖项），同时允许从本机代码调用自定义入口点。对于许多场景来说，这是完美的，而且可以想象，这一点在托管来自本机应用程序的.NET组件的开发人员中变得流行起来。以前不存在的。谢谢你的贡献，@rseanhall。 Two primary PRs: Enable calling get_runtime_delegate from app context Implement hdt_get_function_pointer 两个主要请购单： 启用从应用程序上下文调用get_runtime_delegate 实现hdt_get_函数_指针 Event pipe/事件管道 Event pipe is a new subsystem and API that we added in .NET Core 2.2 to make it possible to perform performance and other diagnostic investigations on any operating system. In .NET 5.0, the event pipe has been extended to enable profilers to write event pipe events. This scenario is critical for instrumenting profilers that previously relied on ETW (on Windows) to monitor application behavior and performance. 事件管道是我们在.NETCore2.2中添加的一个新的子系统和API，它可以在任何操作系统上执行性能和其他诊断调查。在.NET5.0中，事件管道已经扩展，使探查器能够编写事件管道事件。此方案对于检测以前依赖ETW（在Windows上）来监视应用程序行为和性能的探查器至关重要。 Assembly load information is now available via event pipe. This improvement is the start of making similar diagnostics functionality available as is part of .NET Framework, such as the Fusion Log Viewer. You can now use dotnet-trace to collect this information, using the following command: 现在可以通过事件管道获得程序集加载信息。这一改进是使类似的诊断功能可用的开始，它是.NET框架的一部分，如Fusion Log Viewer。现在可以使用以下命令使用dotnet trace收集此信息： dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:4:4 – ./MyApp –my-arg 1 The workflow is described in the dotnet-trace docs. You can see assembly loading information for a simple test app. 在dotnet跟踪文档中描述了工作流。您可以看到一个简单测试应用程序的程序集加载信息。 Microsoft.Extensions.Logging We’ve made improvements to the console log provider in the Microsoft.Extensions.Logging library. You can now implement a custom ConsoleFormatter to exercise complete control over formatting and colorization of the console output. The formatter APIs allow for rich formatting by implementing a subset of the VT-100 (supported by most modern terminals) escape sequences. The console logger can parse out escape sequences on unsupported terminals allowing you to author a single formatter for all terminals. 我们对控制台日志提供程序进行了改进Microsoft.Extensions.Logging图书馆。现在，您可以实现一个自定义的consoleformat来完全控制控制台输出的格式和颜色。格式化程序api通过实现VT-100（大多数现代终端支持）转义序列的子集来实现丰富的格式。控制台记录器可以解析出不受支持的终端上的转义序列，从而允许您为所有终端编写一个格式化程序。 In addition to support for custom formatters, we’ve also added a built-in JSON formatter that emits structured JSON logs to the console. 除了支持自定义格式化程序外，我们还添加了一个内置的JSON格式化程序，它向控制台发送结构化的JSON日志。 Dump debugging/转储调试 Debugging managed code requires knowledge of managed objects and constructs. The Data Access Component (DAC) is a subset of the runtime execution engine that has knowledge of these constructs and can access these managed objects without a runtime. .NET Core process dumps collected on Linux can now be analyzed on Windows using WinDBG or dotnet dump analyze. 调试托管代码需要了解托管对象和构造。数据访问组件（DAC）是运行时执行引擎的一个子集，它了解这些构造，并且可以在不使用运行时的情况下访问这些托管对象。现在可以在Windows上使用WinDBG或dotnet dump analyze分析在Linux上收集的NET核心进程转储。 We’ve also added support for capturing ELF dumps from .NET processes running on macOS. Since ELF is not the native executable (native debuggers like lldb will not work with these dumps) file format on macOS, we have made this an opt-in feature. To enable support for dump collection on macOS, set the environment variable COMPlus_DbgEnableElfDumpOnMacOS=1. The resulting dumps can be analyzed using dotnet dump analyze. 我们还添加了对从运行在macOS上的.NET进程捕获ELF转储的支持。由于ELF不是macOS上的本机可执行文件格式（像lldb这样的本机调试器无法处理这些转储文件），所以我们将其作为一种选择加入特性。要在macOS上启用对转储收集的支持，请设置环境变量COMPlus_dbgenablelfdumponmacos=1。可以使用dotnet dump analyze分析结果转储。 Printing environment information/打印环境信息 As .NET has extended support for new operating systems and chip architectures, people sometimes want a way to print environment information. We created a simple .NET tool that does this, called dotnet-runtimeinfo. 随着.NET扩展了对新操作系统和芯片体系结构的支持，人们有时需要一种打印环境信息的方法。我们创建了一个简单的.NET工具来实现这一点，称为dotnetruntimeinfo。 You can install and run the tool with the following commands. 您可以使用以下命令安装和运行该工具。 dotnet tool install -g dotnet-runtimeinfo dotnet-runtimeinfo The tool produces output in the following form for your environment. 该工具为您的环境生成以下形式的输出。 **.NET information Version: 5.0.0FrameworkDescription: .NET 5.0.0Libraries version: 5.0.0Libraries hash: cf258a14b70ad9069470a108f13765e0e5988f51 Environment information OSDescription: Linux 5.8.6-1-MANJARO-ARM #1 SMP Thu Sep 3 22:01:08 CEST 2020OSVersion: Unix 5.8.6.1OSArchitecture: Arm64ProcessorCount: 6 CGroup info** cfs_quota_us: -1 memory.limit_in_bytes: 9223372036854771712 memory.usage_in_bytes: 2740666368 Runtime and Libraries/运行时和库 There were many improvements across the runtime and libraries. 在运行时和库中有许多改进。 Code quality improvements in RyuJIT/RyuJIT的代码质量改进 There were a lot of improvements to the JIT this release, many of which I shared in previous .NET 5.0 preview posts. In this post, I’m elevating the changes that came from the community. 这次发布的JIT有很多改进，其中很多我在以前的.net5.0预览文章中分享过。在这篇文章中，我将提升社区带来的变化。 Use xmm for stack prolog – dotnet/runtime #32538 — Change to x86/x64 prolog zeroing code. Improvements: Json; TechEmpower. Credit: Ben Adams. Vectorise BitArray for Arm64 – dotnet/runtime #33749 — The BitArray class was updated to include a hardware-accelerated implementation for Arm64 using Arm64 intrinisics. The performance improvements for BitArray are very significant. Credit to @Gnbrkm41. Dynamic generic dictionary expansion feature dotnet/runtime #32270 – Some (maybe most?) uses of generics now have better performance (initial performance findings), based on improving the implementation of low-level (native code) dictionaries used by the runtime to store information about generic types and methods. See Perf: Collection Count() is Slower in Core than the CLR for more information. Credit to @RealDotNetDave for the bug report. Implement Vector.Ceiling / Vector.Floor dotnet/runtime #31993 – Implement Vector.Ceiling / Vector.Floor using x64 and Arm64 intrinsics, per API proposal. Credit to @Gnbrkm41. New, much faster, portable implementation of tailcall helpers. Credit: Jakob Botsch Nielsen (.NET team intern). Reaction from @dsymetweets. Add VectorTableList and TableVectorExtension intrinsics — Credit: @TamarChristinaArm (ARM Holdings) Improved Intel architecture performance using new hardware intrinsics BSF/BSR — Credit @saucecontrol Implement Vector{Size}.AllBitsSet — Credit @Gnbrkm41 Enable eliding some bounds checks — Credit @nathan-moore 将xmm用于堆栈prolog–dotnet/runtime#32538-更改为x86/x64 prolog零位代码。改进：Json；TechEmpower。作者：本·亚当斯。 Arm64的Vectorise BitArray–dotnet/runtime#33749-BitArray类已更新，以包含使用Arm64 Intrinsics的硬件加速的Arm64实现。BitArray的性能改进非常显著。记入@Gnbrkm41。 动态通用字典扩展功能dotnet/runtimeŠ32270–一些（可能是大多数？）基于改进运行时用于存储泛型类型和方法信息的低级（本机代码）字典的实现，泛型的使用现在有了更好的性能（初始性能发现）。有关详细信息，请参阅Perf:Collection Count（）在核心中比CLR慢。缺陷报告归功于@RealDotNetDave。 实施矢量天花板/ 矢量地板dotnet/runtime#31993–实现矢量天花板/ 矢量地板根据API建议使用x64和Arm64内部函数。记入@Gnbrkm41。 新的，更快的，可移植的tailcall助手的实现。作者：Jakob Botsch Nielsen（.NET团队实习生）。@dsymetweets的反应。 添加VectorTableList和tablevectorenextension intrinsics-Credit:@TamarChristinaArm（ARM控股公司） 使用新的硬件内部函数BSF/BSR-Credit@saucecontrol改进了英特尔体系结构的性能 实现向量{Size}.AllBitsSet-Credit@Gnbrkm41 允许省略一些边界检查-信贷@nathan moore Garbage Collector/垃圾收集器 The following improvements were made in the GC. Card mark stealing – dotnet/coreclr #25986 — Server GC (on different threads) can now work-steal while marking gen0/1 objects held live by older generation objects. This means that ephemeral GC pauses are shorter for scenarios where some GC threads took much longer to mark than others. Introducing Pinned Object Heap – dotnet/runtime #32283 — Adds the Pinned Object Heap (POH). This new heap (a peer to the Large Object Heap (LOH)) will allow the GC to manage pinned objects separately, and as a result avoid the negative effects of pinned objects on the generational heaps. Allow allocating large object from free list while background sweeping SOH — Enabled LOH allocations using the free list while BGC is sweeping SOH. Previously this was only using end of segment space on LOH. This allowed for better heap usage. Background GC suspension fixes – dotnet/coreclr #27729 — Suspension fixes to reduce time for both BGC and user threads to be suspended. This reduces the total time it takes to suspend managed threads before a GC can happen. dotnet/coreclr #27578 also contributes to the same outcome. Fix named cgroup handling in docker — Added support to read limits from named cgroups. Previously we only read from the global one. Optimize vectorized sorting – dotnet/runtime #37159 — vectorized mark list sorting in GC which reduces the ephemeral GC pause time (also dotnet/runtime #40613). Generational aware analysis – dotnet/runtime #40322 — generational aware analysis that allows you to determine what old generation objects hold on to younger generation objects thus making them survive and contribute to ephemeral GC pause time. Optimize decommitting GC heap memory pages – dotnet/runtime #35896 — optimized decommit, much better decommit logic and for Server GC took decommit completely out of the “stop the world” phase which reduced blocking GC pause time. GC中进行了以下改进。 卡标记窃取-dotnet/corecrr#25986-服务器GC（在不同的线程上）现在可以在标记老一代对象持有的gen0/1对象时进行偷取。这意味着，对于某些GC线程标记时间比其他线程长得多的场景，短暂的GC暂停更短。 引入固定对象堆-dotnet/runtime#32283-添加固定对象堆（POH）。这个新堆（大对象堆（LOH）的对等体）将允许GC单独管理固定对象，从而避免固定对象对代堆的负面影响。 允许在后台扫描SOH时从空闲列表分配大对象-在BGC扫描SOH时使用空闲列表启用LOH分配。以前这只在LOH上使用段尾空间。这样可以更好地利用堆。 后台GC暂停修复-dotnet/corecrr#27729-暂停修复，以减少BGC和用户线程暂停的时间。这减少了在GC发生之前挂起托管线程所需的总时间。dotnet/corecrr 27578也有助于获得同样的结果。 修正docker中的命名cgroup处理-增加了从命名cgroup读取限制的支持。以前我们只读全球的。 优化矢量化排序–dotnet/runtime#37159-GC中的矢量化标记列表排序，减少短暂的GC暂停时间（dotnet/runtime#40613）。 分代分析-dotnet/runtime#40322-分代分析，允许您确定旧一代对象保留在年轻一代对象上的内容，从而使它们存活下来并导致短暂的GC暂停时间。 优化GC堆内存页的取消提交–dotnet/runtime-优化的取消提交，更好的取消提交逻辑，对于服务器GC，取消提交完全脱离了“停止世界”阶段，从而减少了阻塞GC暂停时间。 The GC now exposes detailed information of the most recent collection, via the GC.GetGCMemoryInfo method. The GCMemoryInfo struct provides information about machine memory, heap memory and the most recent collection, or most recent collection of the kind of GC you specify – ephemeral, full blocking or background GC. GC现在通过GC.GetGCMemoryInfo方法。GCMemoryInfo结构提供有关计算机内存、堆内存和最新集合的信息，或者您指定的GC类型的最新集合—短暂、完全阻塞或后台GC。 The most likely use cases for using this new API are for logging/monitoring or to indicate to a loader balancer that a machine should be taken out of rotation to request a full GC. It could also be used to avoid container hard-limits by reducing the size of caches. 对于一个新的装载机来说，最有可能的情况是使用一个新的装载机来监视一个新的装载机。它还可以通过减少缓存的大小来避免容器硬限制。 Another, small but impactful change, was made to defer the expensive reset memory operation to low-memory situations. We expect these changes in policy to lower the GC latency (and GC CPU usage in general). 另一个小的但有影响的改变是将昂贵的重置内存操作推迟到内存不足的情况。我们期望这些策略上的更改能够降低GC延迟（以及GC CPU的一般使用率）。 Windows Arm64 .NET apps can now run natively on Windows Arm64. This follows the support we added for Linux Arm64 (support for glibc and musl) with .NET Core 3.0. With .NET 5.0, you can develop and run apps on Windows Arm64 devices, such as Surface Pro X. You can already run .NET Core and .NET Framework apps on Windows Arm64, but via x86 emulation. It’s workable, but native Arm64 execution has much better performance. .NET应用程序现在可以在Windows Arm64上以本机方式运行。这是我们为LinuxARM64（支持glibc和musl）添加的.NETCore3.0支持。使用.NET 5.0，您可以在Windows Arm64设备（如Surface Pro X）上开发和运行应用程序。您已经可以在Windows Arm64上运行.NET Core和.NET Framework应用程序，但要通过x86仿真。它是可行的，但是本机Arm64执行有更好的性能。 MSI installers for Arm64 were one of the final changes this release. You can see the .NET 5.0 SDK installer in the following image. Arm64的MSI安装程序是这个版本的最后更改之一。您可以在下图中看到.NET5.0SDK安装程序。 The .NET 5.0 SDK does not currently contain the Windows Desktop components — Windows Forms and WPF — on Windows Arm64. This change was initially shared in the .NET 5.0 Preview 8 post. We are hoping to add the Windows desktop pack for Windows Arm64 in a 5.0 servicing update. We don’t currently have a date to share. Until then, the SDK, console and ASP.NET Core applications are supported on Windows Arm64, but not Windows Desktop components. .NET5.0SDK当前不包含WindowsARM64上的Windows桌面组件—WindowsForms和WPF。这个变化最初是在.NET5.0预览版8中共享的。我们希望在5.0服务更新中添加windowsrm64的Windows桌面包。我们目前没有要分享的日期。在此之前，SDK、控制台和ASP.NETWindows Arm64支持核心应用程序，但不支持Windows桌面组件。 Arm64 Performance/Arm64性能 We’ve been investing significantly in improving Arm64 performance, for over a year. We’re committed to making Arm64 a high-performance platform with .NET. These improvements apply equally to Windows and Linux. Platform portability and consistency have always been compelling characteristics of .NET. This includes offering great performance wherever you use .NET. With .NET Core 3.x, Arm64 has functionality parity with x64 but is missing some key performance features and investments. We’ve resolved that in .NET 5.0, as described in Arm64 Performance in .NET 5.0. 一年多以来，我们一直在大力改进Arm64的性能。我们致力于用.NET使Arm64成为一个高性能平台。这些改进同样适用于Windows和Linux。平台的可移植性和一致性一直是.NET引人注目的特性。无论您在何处使用.NET产品，都可以获得卓越的性能。对于.NETCore3.x，Arm64的功能与x64相当，但缺少一些关键的性能特性和投资。我们已经在.NET5.0中解决了这个问题，如.NET5.0中的Arm64性能所述。 The improvements: Tune JIT optimizations for Arm64 (example) Enable and take advantage of Arm64 hardware intrinsics (example). Adjust performance-critical algorithms in libraries for Arm64 (example). 改进措施： 优化Arm64的JIT优化（示例） 启用并利用Arm64硬件内部函数（示例）。 为Arm64调整库中的性能关键算法（示例）。 See Improving Arm64 Performance in .NET 5.0 for more details. Hardware intrinsics are a low-level performance feature we added in .NET Core 3.0. At the time, we added support for x86-64 instructions and chips. As part of .NET 5.0, we are extending the feature to support Arm64. Just creating the intrinsics doesn’t help performance. They need to be used in performance-critical code. We’ve taken advantage of Arm64 intrinsics extensively in .NET libraries in .NET 5.0. You can also do this in your own code, although you need to be familiar with CPU instructions to do so. 有关更多详细信息，请参见在.NET5.0中改进Arm64性能。 硬件内部函数是我们在.NETCore3.0中添加的一个低级性能特性。当时，我们增加了对x86-64指令和芯片的支持。作为.NET5.0的一部分，我们正在扩展该功能以支持Arm64。仅仅创建内部函数无助于提高性能。它们需要在性能关键的代码中使用。我们在.NET5.0的.NET库中广泛地利用了Arm64内部函数。您也可以在自己的代码中执行此操作，尽管您需要熟悉CPU指令才能这样做。 I’ll explain how hardware intrinsics work with an analogy. For the most part, developers rely on types and APIs built into .NET, like string.Split or HttpClient. Those APIs often take advantage of native operating system APIs, via the P/Invoke feature. P/Invoke enables high-performance native interop and is used extensively in the .NET libraries for that purpose. You can use this same feature yourself to call native APIs. Hardware intrinsics are similar, except instead of calling operating system APIs, they enable you to directly use CPU instructions in your code. It’s roughly equivalent to a .NET version of C++ intrinsics. Hardware intrinsics are best thought of as a CPU hardware-acceleration feature. They provide very tangible benefits and are now a key part of the performance substrate of the .NET libraries, and responsible for many of the benefits you can read about in the .NET 5.0 performance post. In terms of comparison to C++, when .NET intrinsics are AOT-compiled into Ready-To-Run files, the intrinsics have no runtime performance penalty. 我将用一个类比来解释硬件内部机制是如何工作的。在大多数情况下，开发人员依赖于.NET中内置的类型和API，例如字符串。拆分或HttpClient。这些api通常通过P/Invoke特性利用本机操作系统api。P/Invoke支持高性能的本机互操作，并广泛用于.NET库中。您可以自己使用这个特性来调用本机api。硬件内部函数类似，除了不调用操作系统api之外，它们使您能够在代码中直接使用CPU指令。它大致相当于C++内部的.NET版本。硬件内部函数最好被认为是CPU硬件加速特性。它们提供了非常切实的好处，现在是.NET库性能基础的关键部分，并为您在.NET5.0性能文章中了解到的许多好处负责。在与C++的比较中，当.NET内部被编译成可运行的文件时，本质上没有运行时性能的惩罚。 Note: The Visual C++ compiler has an analogous intrinsics feature. You can directly compare C++ to .NET hardware intrinsics, as you can see if you search for _mm_i32gather_epi32 at System.Runtime.Intrinsics.X86.Avx2, x64 (amd64) intrinsics list, and Intel Intrinsics guide. You will see a lot of similarity. 注意：Visual C++编译器具有类似的本质特征。您可以直接比较C++到.NET硬件内部，如您可以看到，如果您在搜索System.Runtime.Intrinsics.X86.Avx2、x64（amd64）内部函数列表和英特尔内部函数指南。你会发现很多相似之处。 We’re making our first big investments in Arm64 performance in 5.0, and we’ll continue this effort in subsequent releases. We work directly with engineers from Arm Holdings to prioritize product improvements and to design algorithms that best take advantage of the Armv8 ISA. Some of these improvements will accrue value to Arm32, however, we are not applying unique effort to Arm32. If you use a Raspberry Pi, you’ll enjoy these improvements if you install the new Arm64 version of Raspberry Pi OS. 我们将在5.0版中对Arm64性能进行首次大投资，并将在后续版本中继续此项工作。我们直接与Arm Holdings的工程师合作，确定产品改进的优先级，并设计最充分利用Armv8 ISA的算法。这些改进中的一些将为Arm32带来价值，但是，我们并没有对Arm32做出独特的努力。如果您使用的是Raspberry Pi，那么如果您安装了新的Arm64版本的Raspberry PiOS，您将享受这些改进。 We expect that Apple will announce new Apple Silicon-based Mac computers any day now. We already have early builds of .NET 6.0 for Apple Silicon and have been working with Apple engineers to help optimize .NET for that platform. We’ve also had some early community engagement on Apple Silicon (Credit @snickler). 我们预计苹果随时都会发布新的基于苹果硅的Mac电脑。我们已经为Apple Silicon开发了早期的.NET6.0版本，并一直在与苹果工程师合作，帮助为该平台优化.NET。我们也有一些关于苹果硅的早期社区活动（Credit@snickler）。 P95+ Latency/P95+延迟 We see an increasing number of large internet-facing sites and services being hosted on .NET. While there is a lot of legitimate focus on the requests per second (RPS) metric, we find that no big site owners ask us about that or require millions of RPS. We hear a lot about latency, however, specifically about improving P95 or P99 latency. Often, the number of machines or cores that are provisioned for (and biggest cost driver of) a site are chosen based on achieving a specific P95 metric, as opposed to say P50. We think of latency as being the true “money metric”. 我们看到越来越多面向互联网的大型网站和服务被托管在.NET上。虽然人们对每秒请求数（RPS）指标有很多合理的关注，但我们发现没有大的站点所有者向我们询问这一点，也没有需要数百万的RPS。然而，我们听到很多关于延迟的消息，特别是关于改善P95或P99延迟的内容。通常，为一个站点配置的机器或核心的数量（以及最大的成本动因）是基于实现特定的P95指标而选择的，而不是P50。我们认为延迟是真正的“金钱指标”。 Our friends at Stack Overflow do a great job of sharing data on their service. One of their engineers, Nick Craver, recently shared improvements they saw to latency, as a result of moving to .NET Core: 我们在Stack Overflow的朋友在共享他们的服务上的数据方面做得很好。他们的一位工程师尼克·克雷弗（Nick Craver）最近分享了他们发现的延迟改进，这是迁移到.NET核心的结果： The median page render time for questions dropped from about 21 ms (we were up a bit lately due to GC) to ~15ms. The 95th percentile dropped from ~40ms to ~30ms (same measurement). 99th dropped from ~60ms to ~45ms. Not too shabby, given we haven’t optimized anything at all yet. pic.twitter.com/MMHjI9wkuL — Nick Craver (@Nick_Craver) March 31, 2020 Pinned objects have been a long-term challenge for GC performance, specifically because they accelerate (or cause) memory fragmentation. We’ve added a new GC heap for pinned objects. The pinned object heap is based on the assumption that there are very few pinned objects in a process but that their presence causes disproportionate performance challenges. It makes sense to move pinned objects — particularly those created by .NET libraries as an implementation detail — to a unique area, leaving the generational GC heaps with few or no pinned objects, and with substantially higher performance as a result. 固定对象一直是GC性能的长期挑战，特别是因为它们加速（或导致）内存碎片。我们为固定对象添加了一个新的GC堆。固定对象堆是基于这样一个假设，即在一个进程中只有很少的固定对象，但是它们的存在会导致不成比例的性能挑战。将固定对象（尤其是作为实现细节由.NET库创建的那些对象）移动到一个独特的区域是有意义的，这样就使得生成的GC堆只有很少或没有固定的对象，因此性能大大提高。 More recently, we’ve been attacking long-standing challenges in the GC. dotnet/runtime #2795 applies a new approach to GC statics scanning that avoids lock contention when it is determining liveness of GC heap objects. dotnet/runtime #25986 uses a new algorithm for balancing GC work across cores during the mark phase of garbage collection, which should increase the throughput of garbage collection with large heaps, which in turn reduces latency. 最近，我们一直在攻克GC中长期存在的挑战。dotnet/runtime#2795对GC静态扫描应用了一种新的方法，在确定GC堆对象的活动性时，可以避免锁争用。dotnet/runtime#25986在垃圾收集的标记阶段使用了一种新的算法来平衡内核之间的GC工作，这将提高具有大堆的垃圾收集的吞吐量，从而减少延迟。 Improving tiered compilation performance/提高分层编译性能 We’ve been working on improving tiered compilation for multiple releases. We continue to see it as a critical performance feature, for both startup and steady-state performance. We’ve made two big improvements to tiered compilation this release. 我们一直致力于改进多个版本的分层编译。我们继续把它看作是一个关键的性能特性，对于启动和稳态性能都是如此。在这个版本中，我们对分层编译做了两大改进。 The primary mechanism underlying tiered compilation is call counting. Once a method is called n times, the runtime asks the JIT to recompile the method at higher quality. From our earliest performance analyses, we knew that the call-counting mechanism was too slow, but didn’t see a straightforward way to resolve that. As part of .NET 5.0, we’ve improved the call counting mechanism used by tiered JIT compilation to smooth out performance during startup. In past releases, we’ve seen reports of unpredictable performance during the first 10-15s of process lifetime (mostly for web servers). That should now be resolved. 分层编译的主要机制是调用计数。一旦一个方法被调用n次，运行时就会要求JIT以更高的质量重新编译该方法。从我们最早的性能分析中，我们知道调用计数机制太慢了，但是没有找到一种简单的方法来解决这个问题。作为.NET5.0的一部分，我们改进了分层JIT编译所使用的调用计数机制，以平滑启动期间的性能。在过去的版本中，我们看到过在进程生命周期的前10-15秒内性能不可预测的报告（主要针对web服务器）。现在应该解决这个问题。 Another performance challenge we found was using tiered compilation for methods with loops. The fundamental problem is that you can have a cold method (only called once or a few times;$lt; n) with a loop that iterates many times. We call this pathological scenario “cold method; hot loop”. It is easy to imagine this happening with the Main method of an application. As a result, we disabled tiered compilation for methods with loops by default. Instead, we enabled applications to opt into using tiered compilation with loops. PowerShell is an application that chose to do this, after seeing high single-digit performance improvements in some scenarios.

To address methods with loops better, we implemented on-stack replacement (OSR). This is similar to a feature that the Java Virtual Machines has, of the same name. OSR enables code executed by a currently running method to be re-compiled in the middle of method execution, while those methods are active “on-stack”. This feature is currently experimental and opt-in, and on x64 only.

To use OSR, multiple features must be enabled. The PowerShell project file is a good starting point. You will notice that tiered compilation and all quick-jit features are enabled. In addition, you need to set the COMPlus_TC_OnStackReplacement environment variable to 1.

Alternatively, you can set the following two environment variables, assuming all other settings have their default values:

COMPlus_TC_QuickJitForLoops=1

COMPlus_TC_OnStackReplacement=1

We do not intend to enable OSR by default in .NET 5.0 and have not yet decided if we will support it in production.

Support for ICU on Windows/在Windows上支持ICU
We use the ICU library for Unicode and globalization support, previously only on Linux and macOS. We are now using this same library on Windows 10. This change makes the behavior of globalization APIs such as culture-specific string comparison consistent between Windows 10, macOS, and Linux. We also use ICU with Blazor WebAssembly.

Expanding System.DirectoryServices.Protocols to Linux and macOS/扩大System.DirectoryServices.Protocols.协议到Linux和macOS
We’ve been adding cross-platform support for System.DirectoryServices.Protocols. This includes support for Linux and support for macOS. Windows support was pre-existing.

System.DirectoryServices.Protocols is a lower-level API than System.DirectoryServices, and enables (or can be used to enable) more scenarios. System.DirectoryServices includes Windows-only concepts/implementations, so it was not an obvious choice to make cross-platform. Both API-sets enable controlling and interacting with a directory service server, like LDAP or Active Directory.

System.DirectoryServices.Protocols.协议是一个比系统目录服务，并启用（或可用于启用）更多方案。系统目录服务只包含Windows的概念/实现，所以跨平台的选择并不明显。这两个API集都支持对目录服务服务器（如LDAP或activedirectory）的控制和交互。

System.Text.Json
System.Text.Json has been significantly improved in .NET 5.0 to improve performance, reliability, and to make it easier for people to adopt that are familiar with Newtonsoft.Json. It also includes support for deserializing JSON objects to records.

System.Text.Json文件在.NET5.0中得到了显著的改进，以提高性能、可靠性，并使人们更容易采用熟悉的Newtonsoft.Json. 它还支持将JSON对象反序列化为记录。

If you are looking at using System.Text.Json as an alternative to Newtonsoft.Json, you should check out the migration guide. The guide clarifies the relationship between these two APIs. System.Text.Json is intended to cover many of the same scenarios as Newtonsoft.Json, but it’s not intended to be a drop-in replacement for or achieve feature parity with the popular JSON library. We try to maintain a balance between performance and usability, and bias to performance in our design choices.

HttpClient extension methods
JsonSerializer extension methods are now exposed on HttpClient and greatly simplify using these two APIs together. These extension methods remove complexity and take care of a variety of scenarios for you, including handling the content stream and validating the content media type. Steve Gordon does a great job of explaining the benefits in Sending and receiving JSON using HttpClient with System.Net.Http.Json.

JsonSerializer扩展方法现在公开在HttpClient上，并极大地简化了这两个api的结合使用。这些扩展方法消除了复杂性，并为您处理各种场景，包括处理内容流和验证内容媒体类型。stevegordon很好地解释了使用HttpClient发送和接收JSON的好处系统.Net.Http.Json文件。

The following example deserializes weather forecast JSON data into a Forecast record, using the new

This code is compact! It is relying on top-level programs and records from C# 9 and the new GetFromJsonAsync() extension method. The use of foreach and await in such close proximity might be make you wonder if we’re going to add support for streaming JSON objects. I really hope so.

You can try this on your own machine. The following .NET SDK commands will create a weather forecast service using the WebAPI template. It will expose the service at the following URL by default: https://localhost:5001/WeatherForecast. This is the same URL used in the sample.

rich@thundera ~ % dotnet new webapi -o webapi
rich@thundera ~ % cd webapi
rich@thundera webapi % dotnet run
Make sure you’ve run dotnet dev-certs https --trust first or the handshake between client and server won’t work. If you’re having trouble, see Trust the ASP.NET Core HTTPS development certificate.

You can then run the previous sample.

rich@thundera ~ % git clone https://gist.github.com/3b41d7496f2d8533b2d88896bd31e764.git weather-forecast
rich@thundera ~ % cd weather-forecast
rich@thundera weather-forecast % dotnet run
9/9/2020 12:09:19 PM; 24C; Chilly9/10/2020 12:09:19 PM; 54C; Mild9/11/2020 12:09:19 PM; -2C; Hot9/12/2020 12:09:19 PM; 24C; Cool9/13/2020 12:09:19 PM; 45C; Balmy
Improved support for immutable types

There are multiple patterns for defining immutable types. Records are just the newest one. JsonSerializer now has support for immutable types.

In this example, you’ll see the serialization with an immutable struct.

using System;using System.Text.Json;using System.Text.Json.Serialization;var json = "{“date”:“2020-09-06T11:31:01.923395-07:00”,“temperatureC”:-1,“temperatureF”:31,“summary”:“Scorching”} ";
var options = new JsonSerializerOptions(){
PropertyNameCaseInsensitive = true,
IncludeFields = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase};var forecast = JsonSerializer.Deserialize(json, options);Console.WriteLine(forecast.Date);Console.WriteLine(forecast.TemperatureC);Console.WriteLine(forecast.TemperatureF);Console.WriteLine(forecast.Summary);var roundTrippedJson = JsonSerializer.Serialize(forecast, options);Console.WriteLine(roundTrippedJson);public struct Forecast{
public DateTime Date {get;}
public int TemperatureC {get;}
public int TemperatureF {get;}
public string Summary {get;}
[JsonConstructor]
public Forecast(DateTime date, int temperatureC, int temperatureF, string summary) => (Date, TemperatureC, TemperatureF, Summary) = (date, temperatureC, temperatureF, summary);}
Note: The JsonConstructor attribute is required to specify the constructor to use with structs. With classes, if there is only a single constructor, then the attribute is not required. Same with records.

It produces the following output:

rich@thundera jsonserializerimmutabletypes % dotnet run
9/6/2020 11:31:01 AM
-131Scorching{“date”:“2020-09-06T11:31:01.923395-07:00”,“temperatureC”:-1,“temperatureF”:31,“summary”:“Scorching”}
Support for records/记录支持
JsonSerializer support for records is almost the same as what I just showed you for immutable types. The difference I want to show here is deserializing a JSON object to a record that exposes a parameterized constructor and an optional init property.

JsonSerializer对记录的支持与我刚才向您展示的不可变类型几乎相同。我想在这里展示的区别是将JSON对象反序列化为一个记录，该记录公开了一个参数化的构造函数和一个可选的init属性。

Here’s the program, including the record definition:

It produces the following output:

rich@thundera jsonserializerrecords % dotnet run
{“Date”:“2020-09-12T18:24:47.053821-07:00”,“TemperatureC”:40,“Summary”:“Hot!”}Forecast { Date = 9/12/2020 6:24:47 PM, TemperatureC = 40, Summary = Hot! }
Improved Dictionary<K,V> support
JsonSerializer now supports dictionaries with non-string keys. You can see what this looks like in the following sample. With .NET Core 3.0, this code compiles but throws a NotSupportedException.

It produces the following output.

rich@thundera jsondictionarykeys % dotnet run
{“0”:“zero”,“1”:“one”,“2”:“two”,“3”:“three”,“5”:“five”,“8”:“eight”,“13”:“thirteen”,“21”:“twenty one”,“34”:“thirty four”,“55”:“fifty five”}
fifty five
Support for fields/对字段的支持
JsonSerializer now supports fields. This change was contributed by @YohDeadfall. Thanks!

You can see what this looks like in the following sample. With .NET Core 3.0, JsonSerializer fails to serialize or deserialize with types that use fields. This is a problem for existing types that have fields and cannot be changed. With this change, that’s no longer an issue.

Produces the following output:

rich@thundera jsonserializerfields % dotnet run
9/6/2020 11:31:01 AM
-131Scorching{“date”:“2020-09-06T11:31:01.923395-07:00”,“temperatureC”:-1,“temperatureF”:31,“summary”:“Scorching”}
Preserving references in JSON object graphs/在JSON对象图中保存引用
JsonSerializer has added support for preserving (circular) references within JSON object graphs. It does this by storing IDs that can be reconstituted when a JSON string is deserialized back to objects.

JsonSerializer增加了对在JSON对象图中保留（循环）引用的支持。它通过存储可以在JSON字符串反序列化回对象时重新构造的id来实现这一点。

Performance/性能
JsonSerializer performance is significantly improved in .NET 5.0. Stephen Toub covered some JsonSerializer improvements in his Performance Improvements in .NET 5 post. I also covered Json Performance in more detailed in the .NET 5.0 RC1 post.

JsonSerializer在.NET5.0中的性能得到了显著的提高。StephenToub在.NET5的文章中介绍了一些JsonSerializer的改进。我还在.NET5.0RC1文章中更详细地介绍了Json性能。

Application deployment/应用程序部署
After writing or updating an application, you need to deploy it for your users to benefit. This might be to a web server, a cloud service, or client machine, and might be the result of a CI/CD flow using a service like Azure DevOps or GitHub Actions.

We strive to provide first-class deployment capabilities that naturally align with the application types. For .NET 5.0, we focused on improving single file applications, reducing container size for docker multi-stage builds, and providing better support for deploying ClickOnce applications with .NET Core.

Containers/容器
We consider containers to be the most important cloud trend and have been investing significantly in this modality. We’re investing in containers in multiple ways, at multiple levels of the .NET software stack. The first is our investment in fundamentals, which is increasingly influenced by the container scenario and by developers who deploy containerized apps.

We’re making it easier to work with container orchestrators. We’ve added OpenTelemetry support so that you can capture distributed traces and metrics from your application. dotnet-monitor is a new tool that is intended as the primary way to access diagnostic information from a .NET process. In particular, we have started building a container variant of dotnet-monitor that you can use as an application sidecar. Last, we are building dotnet/tye as way to improve microservices developer productivity, both for development and deploying to a Kubernetes environment.

The .NET runtime now has support for cgroup v2, which we expect will become an important container-related API beyond 2020. Docker currently uses cgroup v1 (which is already supported by .NET). In comparison, cgroup v2 is simpler, more efficient, and more secure than cgroup v1. You can learn more about cgroup and Docker resource limits from our 2019 Docker update. Linux distros and containers runtimes are in the process of adding support for cgroup v2. .NET 5.0 will work correctly in cgroup v2 environments once they become more common. Credit to Omair Majid, who supports .NET at Red Hat.

We’re now publishing Windows Server Core images, in addition to Nano Server. We added Server Core because we heard feedback from customers who wanted a .NET image that was fully compatible with Windows Server. If you need that, then this new image is for you. It’s supported for the combination of: Windows Server 2019 Long-Term Servicing Channel (LTSC), .NET 5.0, and x64. We’ve made other changes that reduce the size of Windows Server Core images. Those improvements make a big difference but were made after Windows Server 2019 was released. They will, however, benefit the next Windows Server LTSC release.

As part of the move to “.NET” as the product name, we’re now publishing .NET Core 2.1, 3.1 and .NET 5.0 images to the mcr.microsoft.com/dotnet family of repos, instead of mcr.microsoft.com/dotnet/core. We will continue dual publishing .NET Core 2.1 and 3.1 to the previous location while those versions are supported. .NET 5.0 images will only be published to the new locations. Please update your FROM statements and scripts accordingly.

As part of .NET 5.0, we re-based the SDK image on top of the ASP.NET image instead of buildpack-deps to dramatically reduces the size of the aggregate images you pull in multi-stage build scenarios.

This change has the following benefit for multi-stage builds, with a sample Dockerfile:

Multi-stage build costs with Ubuntu 20.04 Focal:

Ubuntu 20.04 Focal的多阶段构建成本：

Pull Image Before After
sdk:5.0-focal 268 MB 232 MB
aspnet:5.0-focal 64 MB 10 KB (manifest only)

Multi-stage build costs with Debian 10 Buster:

Debian 10 Buster的多阶段构建成本：

Pull Image Before After
sdk:5.0 280 MB 218 MB
aspnet:5.0 84 MB 4 KB (manifest only)

See dotnet/dotnet-docker #1814 for more detailed information.

This change helps multi-stage builds, where the sdk and the aspnet or runtime image you are targeting are the same version (we expect that this is the common case). With this change, the aspnet pull (for example), will be a no-op, because you will have pulled the aspnet layers via the initial sdk pull.

We made similar changes for Alpine and Nano Server. There is no buildpack-deps image for either Alpine or Nano Server. However, the sdk images for Alpine and Nano Server were not previously built on top of the ASP.NET image. We fixed that. You will see significant size wins for Alpine and Nano Server as well with 5.0, for multi-stage builds.

Single file applications/单文件应用程序
Single file applications are published and deployed as a single file. The app and its dependencies are all included within that file. When the app is run, the dependencies are loaded directly from that file into memory (with no performance penalty).

In .NET 5.0, single file apps are primarily focused on Linux (more on that later). They can be either framework-dependent or self-contained. Framework-dependent single file apps can be very small, by relying on a globally-installed .NET runtime. Self-contained single-file apps are larger (due to carrying the runtime), but do not require installation of the .NET runtime as an installation pre-step and will just work as a result. In general, framework-dependent is good for development and enterprise environments, while self-contained is often a better choice for ISVs.

We produced a version of single-file apps with .NET Core 3.1. It packages binaries into a single file for deployment and then unpacks those files to a temporary directory to load and execute them. There may be some scenarios where this approach is better, but we expect that the solution we’ve built for 5.0 will be preferred and a welcome improvement.

We had multiple hurdles to overcome to create a true single-file solution. Key tasks were creating a more sophisticated application bundler and teaching the runtime to load assemblies out of binary resources. We also ran into some hurdles that we could not clear.

On all platforms, we have a component called “apphost”. This is the file that becomes your executable, for example myapp.exe on Windows or ./myapp on Unix-based platforms. For single file apps we created a new apphost we call “superhost”. It has the same role as the regular apphost, but also includes a statically-linked copy of the runtime. The superhost is a fundamental design point of our single file approach. This model is the one we use on Linux with .NET 5.0. We were not able to implement this approach on Windows or macOS, due to various operating system constraints. We do not have a superhost on Windows or macOS. On those operating systems, the native runtime binaries (~3 of them) sit beside the single file app (resulting in “not single file”). We’ll revisit this situation in .NET 6.0, however, we expect the problems we ran into to remain challenging.

You can use the following commands to produce single-file apps.

Framework-dependent single-file app:

dotnet publish -r linux-x64 --self-contained false /p:PublishSingleFile=true

Self-contained single-file app:

dotnet publish -r linux-x64 --self-contained true /p:PublishSingleFile=true

You can also configure single file publishing with a project file.

Exe net5.0 linux-x64 true true You can experiment with assembly trimming to reduce the size of your application. It can break apps, by over-trimming, so it is recommended to test your app thoroughly after using this feature. Assembly trimming also removes ahead-of-time-compiled read-to-run native code (for the assemblies that are trimmed), which is there primarily for performance. You will want to test your application for performance after trimming. You can ready-to-run-compile your app after trimmng by using PublishReadyToRun property (and setting to true).

Notes:

Apps are OS and architecture-specific. You need to publish for each configuration (Linux x64, Linux Arm64, Windows x64, …).

Configuration files (like *.runtimeconfig.json) are included in the single file. You can place an additional config file beside the single file, if needed (possibly for testing).

.pdb files are not included in the single file by default. You can enable PDB embedding with the embed property.

The IncludeNativeLibrariesForSelfExtract property can be used to embed native runtime binaries, on Windows and macOS, however, they have to be unpacked to temporary storage at runtime. This feature is not recommended for genereal use.

IncludeNativeLibrariesForSelfExtract属性可用于在Windows和macOS上嵌入本机运行时二进制文件，但是，它们必须在运行时解压到临时存储中。一般不建议使用此功能。

ClickOnce/一次点击
ClickOnce has been a popular .NET deployment option for many years. It’s now supported for .NET Core 3.1 and .NET 5.0 Windows apps. We knew that many people would want to use ClickOnce for application deployment when we added Windows Forms and WPF support to .NET Core 3.0. In the past year, the .NET and Visual Studio teams worked together to enable ClickOnce publishing, both at the command line and in Visual Studio.

ClickOnce多年来一直是一个流行的.NET部署选项。现在.NET Core 3.1和.NET 5.0 Windows应用程序支持它。我们知道，当我们将Windows窗体和WPF支持添加到.NETCore3.0时，许多人都希望使用ClickOnce进行应用程序部署。在过去的一年中，.NET和visualstudio团队合作，在命令行和visualstudio中启用ClickOnce发布。

We had two goals from the start of the project:

Enable a familiar experience for ClickOnce in Visual Studio.

Enable a modern CI/CD for ClickOnce publishing with command-line flows, with either MSBuild or the Mage tool.

It’s easiest to show you the experience in pictures.

Let’s start with the Visual Studio experience, which is centered around project publishing.

The primary deployment model we’re currently supporting is framework dependent apps. It is easy to take a dependency on the .NET Desktop Runtime (that’s the one that contains WPF and Windows Forms). Your ClickOnce installer will install the .NET runtime on user machines if it is needed. We also intend to support self-contained and single file apps.

You might wonder if you can still be able to take advantage of ClickOnce offline and updating features. Yes, you can.

The big change with Mage is that it is now a .NET tool, distributed on NuGet. That means you don’t need to install anything special on your machine. You just need the .NET 5.0 SDK and then you can install Mage as a .NET tool. You can use it to publish .NET Framework apps as well, however, SHA1 signing and partial trust support have been removed.

Mage的最大变化是它现在是一个.NET工具，分布在NuGet上。这意味着你不需要在你的机器上安装任何特殊的东西。您只需要.NET5.0SDK，然后就可以将Mage安装为.NET工具。您也可以使用它发布.NET Framework应用程序，但是，SHA1签名和部分信任支持已被删除。

The Mage installation command follows:

Mage安装命令如下：

dotnet tool install -g Microsoft.DotNet.Mage
After you’ve produced and distributed your ClickOnce installer, your users will see the familiar ClickOnce installation dialogs.

Your users will see the update dialog when you make updates available.

Closing
.NET 5.0 is another big release that should improve many aspects of your use with .NET. We have enabled a broad set of improvements, ranging from single file applications, to performance, to Json serialization usability to Arm64 enablement. While today may be your first day with .NET 5.0, we’ve been running .NET 5.0 in production at Microsoft for months. We have confidence that it is ready for you to use, to run your business and power your apps. The new language improvements in C# 9 and F# 5 should make your code more expressive and easier to write. .NET 5.0 is also a great choice for your existing apps. In many cases, you can upgrade without much effort.

If you’re interested in performance, you may be interested in our progress with the TechEmpower benchmarks. Looking back, you can see that .NET Core 3.1 is doing pretty well with round 19, the latest round. We’re looking forward to seeing .NET 5.0 in the upcoming round 20. The new ranking will be something to watch out for when round 20 is finalized and published.

The improvements in .NET 5.0 are the result of efforts by many people, working collaboratively across the world and in many time zones, on GitHub. Thanks to everyone who contributed to this release. And don’t worry, there are lots of opportunities to contribute. The .NET 5.0 release has come to a close, but the next release has already started.

.NET5.0是另一个大的版本，它可以改善你在.NET中使用的许多方面。我们已经实现了一系列广泛的改进，从单文件应用程序到性能，从Json序列化可用性到Arm64启用。虽然今天可能是您使用.NET5.0的第一天，但我们已经在Microsoft的生产环境中运行了几个月的.NET5.0。我们有信心，它已经准备好供您使用、运行您的业务和为您的应用程序提供动力。C#9和F#5中新的语言改进应该使您的代码更具表现力，更易于编写。NET5.0对于你现有的应用来说也是一个很好的选择。在许多情况下，您可以不费吹灰之力就进行升级。

NET5.0的改进是许多人努力的结果，他们在世界各地和许多时区，在GitHub上协同工作。感谢所有为这次发布做出贡献的人。别担心，有很多机会可以贡献。.NET5.0版本已经接近尾声，但是下一个版本已经开始了。

• 0
点赞
• 0
评论
• 0
收藏
• 扫一扫，分享海报

06-27 833

11-11 1万+
07-28 81
05-20 281
11-18 1444
04-15
11-13
04-16