We are very happy to release .NET 6 RC (Release Candidate) 2. It is the second of two "go live" candidate releases supported in the production environment. In the past few months, the team has been focusing on quality improvement. There are many new features in this version, but we will fully integrate them when we are near the end. The team is currently verifying the end-to-end workflow to find areas where the design intent and technical reality have not yet fully matched. This resulted in the maintainers in the team having to modify the bug to achieve this goal.
We heard from users that upgrading a production site to .NET 6 is both "boring" (non-event) and "exciting" (significant performance improvement). Not surprisingly, we believe that RC2 will continue to maintain this trend.
.NET 6 Release Candidate2 for Linux, macOS and Windows.
- installer and binary file
- container image
- Linux package
- Release Notes
- API diff
- Known issues
- GitHub issue tracker
Please refer to the .NET MAUI and ASP.NET Core posts for more details on the new features of the client and web application scenarios.
The .NET Conference is a free, three-day virtual developer event to celebrate the major version of .NET. This year, .NET 6 will be released at the .NET conference from November 9th to 11th. We look forward to you note of the date the time to listen . Visual Studio 2022 Preview 5 is also released today, and they also announced that they will hold a release event on November 8. You can read all about it on the Visual Studio blog
We are in this interesting part of the cycle to support the production of new versions. We sincerely encourage it. If you need guidance on how to proceed, you can contact us at dotnet@microsoft.com. Many companies have already started contact, and some have already started production. We also help the Microsoft team to run on the RC version. Some Microsoft teams are already in production on RC1, and we look forward to more help on RC2. This includes the .NET website .
.NET 6 RC2 has been tested and is supported by Visual Studio 2022 Preview 5 , which is also released today. Visual Studio 2022 will support .NET 6, while Visual Studio 2019 will not. Similarly, MSBuild 17.x will support it, but 16.x will not. If you want to use .NET 6, you need to upgrade to Visual Studio 2022.
The Mac version of Visual Studio 2022 is currently not compatible with .NET 6 RC2. We are solving this problem.
Check out the new conversation post for in-depth engineer-to-engineer discussions on the latest .NET features.
.NET 6 RC1 Post focuses on basic functions, many of which cannot be fully implemented until .NET 7. This article focuses on related improvements in C# 10 and templates. It also includes macOS and Windows Arm64 updates (including major changes). let's see.
C#10
C# 10 is an important part of the .NET 6 version. To a large extent, C# 10 is a further evolution of existing concepts and functions (such as records and patterns). It also includes features-global usage and file-scoped namespaces-which can help you simplify your code and write fewer boilerplate files. These specific improvements are the basis for the template changes discussed later in this article. You can see the example in this section in I will add more examples in the last post of .NET 6.
Record structs
C# 10 adds support for Record structs. This new feature is similar to C# 9 (class-based) logging, but there are some major differences. In most cases, Record structs are added for completeness, so that the structure can enjoy the same record advantages as the class. However, the team did not simply structure the records, but decided to keep the structure records consistent with ValueTuple, just as the class records match. Due to this design method, the properties of Record structs are mutable by default, while the properties of the Record class are immutable. However, you can declare a read-only Record structs that is immutable and matches the semantics of the record class.
At a high level, Record structs will not replace the Record class, and we discourage the migration of the Record class to Record structs. The guidelines for using class vs structure also apply to Record classes and Record structs. In other words, before choosing to use Record, you should choose between classes and structures.
Let's see how the Record structs are different Record class
Battery battery = new("CR2032", 0.235, 100);
WriteLine(battery);
while (battery.RemainingCapacityPercentage > 0)
{
battery.RemainingCapacityPercentage--;
}
WriteLine(battery);
public record struct Battery(string Model, double TotalCapacityAmpHours, int RemainingCapacityPercentage);
This example of Record structs produces the following result
Battery { Model = CR2032, TotalCapacityAmpHours = 0.235, RemainingCapacityPercentage = 100 }
Battery { Model = CR2032, TotalCapacityAmpHours = 0.235, RemainingCapacityPercentage = 0 }
As mentioned earlier, the most obvious difference is that the record structure attributes are variable by default. This is the main difference apart from structure and record structure syntax. I also rewrote this example with a read-only record structure, as shown below.
Battery battery = new("CR2032", 0.235, 100);
WriteLine(battery);
while (battery.RemainingCapacityPercentage > 0)
{
Battery updatedBattery = battery with {RemainingCapacityPercentage = battery.RemainingCapacityPercentage - 1};
battery = updatedBattery;
}
WriteLine(battery);
public readonly record struct Battery(string Model, double TotalCapacityAmpHours, int RemainingCapacityPercentage);
You will see that it almost me as C # (class) Record Example 9 released same.
Let's review the record of C# 9. They provide a for defining data-oriented classes with similar structure . They favor immutability, while providing concise syntax—with expressions—for immutable and friendly copying. People may be surprised that we start to use classes to implement similar structure functions. Most of the time, developers use classes instead of structures because of reference passing rather than value semantics. In most cases, classes are the best choice and are easy to use.
Structure records are very similar to class records:
- They use the same syntax (except for struct or class in the definition).
- They allow custom member definitions (new in C#10) to use fields on (by default) attribute members.
- They allow the use of init or variable attributes to customize member behavior.
- They support expressions. In fact, since C# 10, all structure types support expressions.
Structure records are different from class records:
- Record structs can be defined with Record structs or read-only Record structs.
- The record class is defined by the record or record class.
- By default, the Record structs property is variable (get/set).
- By default, record class attributes are immutable (get/init).
The asymmetric (immutable) behavior between Record structs and Record classes may surprise some readers, or even disgust them. I'll try to explain behind the design ideas . Because the semantics are passed by value, the benefits of the structure from immutability are almost inferior to the class. For example, if the structure is a key in a dictionary, the key (a copy of the structure) is immutable and can only be searched by equality. At the same time, the design team believes that ValueTuple can be regarded as an anonymous record structure, and Record structs can be regarded as a derivative of ValueTuple. This only works if the record structure contains variability and supporting fields, which is exactly what the team decided to do. In addition, the inclusion of variability reflects the difference in structure and class.
If you prefer the immutable behavior of the record structure, you can get it by adding the readonly keyword.
Looking at structs generally, key functionality is common:
- The equality check provided at runtime is the same for all structures.
- All structures can be used with expressions to create non-mutated copies, which is a new feature in C# 10.
Global usings
Global using allows you to specify a namespace that you want to be available in all source files, as if it were declared in each source file. It can also be used to use static and alias together. This feature allows the use of a common set of using statements and expands to more using lines that are no longer needed. This is most relevant to namespaces, but can be used for any namespace.
The following syntax can be used in various usage forms:
- global using System;
- global using static System.Console;
- global using E = System.Environment;
These declarations only need to be declared once in the compilation. There are four modes to declare global using.
- In Program.cs, the root using statements are upgraded to global using to make them global to the entire program.
- In the globaluses.cs file (or similar name), centrally manage all global using statements.
- In the project file, use the following syntax.
- In your project file, use the statement (for the MSBuild SDK that your application depends on) to enable the default platform, the syntax is as follows.
The following MSBuild syntax can be used in place of the .cs file (using a method similar to the previous example).
- < Using Include="System"/ >
- < Using Include="System.Console" Static="True"/ >
- < Using Include="System.Environment" Alias="E"/ >
You can enable the implicit using statement defined by the platform in the <PropertyGroup>.
- < ImplicitUsings > enable < /ImplicitUsings >
implicitly uses a different MSBuild SDK . Microsoft.NET.Sdk defines a basic set, and other SDKs define additional sets.
If you use the MSBuild function, you can see the valid results in the files generated in the obj directory, as shown below.
PS C:\Users\rich\app> type .\app.csproj | findstr Using
<ImplicitUsings>enable</ImplicitUsings>
<Using Include="System.Console" Static="True"/>
<Using Include="System.Environment" Alias="E"/>
PS C:\Users\rich\app> type .\obj\Debug\net6.0\app.GlobalUsings.g.cs
// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.NET.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;
global using E = global::System.Environment;
global using static global::System.Console;
As you can see, Microsoft.NET.Sdk has added several global using statements in the .globalusings.g.cs file. Please note that the global :: operator is not required, in order to understand the generated syntax, you can safely ignore it.
file and namespace declaration
The declaration of file scope namespaces is another feature of C# 10 designed to reduce indentation and line count.
The syntax of this function is as follows:
namespaceFoo;
It is an alternative to the traditional three-line grammar:
namespaceFoo
{
}
Three-line syntax can be nested. Single-line syntax does not support nesting. There can only be one file-scoped declaration per file. It must precede all types defined in the file, much like a three-line syntax.
The namespace is not compatible with the top-level statement. The top-level statement exists in the top-level namespace. This also means that if you add additional methods to the Program class, using the partial class syntax, the partial Program class also needs to be in the top-level namespace.
This feature is very similar to added to 8 one-way C # using statement .
Const and interpolated string
Now you can assign the interpolated string to a const variable. Interpolated strings are intuitive to use and read, and can be used anywhere. They can now be used with const, provided that the placeholder value is also constant.
The following example demonstrates an example of possible use:
const string Bar = "Bar";
const string DoubleBar = $"{Bar}_{Bar}";
WriteLine(DoubleBar);
string interpolation, which are described in C# 10 and .NET 6.
Extended attribute mode
You can now reference nested attributes or fields in the attribute mode. For example, the following pattern is now legal:
{Prop1.Prop2: pattern }
Previously, you needed to use a more detailed form:
{Prop1:{Prop2: pattern }}
You can see the use of this more compact form in the example below, for example using Reading.PM25.
List<Status> statuses = new()
{
new(Category.Normal, new(20, false, 20)),
new(Category.Warning, new(20, false, 60)),
new(Category.Danger, new(20, true, 60)),
new(Category.Danger, new(100, false, 20))
};
foreach (Status status in statuses)
{
string message = status switch
{
{Category: Category.Normal} => "Let the good times roll",
{Category: Category.Warning, Reading.PM25: >50 and <100} => "Check the air filters",
{Reading.PM25: >200 } => "There must be a fire somewhere. Don't go outside.",
{Reading.SmokeDetected: true } => "We have a fire!",
{Category: Category.Danger} => "Something is badly wrong",
_ => "Unknown status"
};
Console.WriteLine(message);
}
record struct Reading(int Temperature, bool SmokeDetected, int PM25);
record struct Status(Category Category, Reading Reading);
enum Category
{
Normal,
Warning,
Danger
}
.NET SDK: Modern C# project template
We updated the .NET SDK template in Preview 7, using the latest C# features and modes. There was important feedback on these changes, partly because the build started to fail. implicit use of (aka opt-out) for .NET6 (NET 6.0) projects (including applications updated from .NET 5 to .NET 6). that has changed . We have updated the SDK, so all new features are optional. The response to this change (made in RC1) was positive.
There are also feedback that some people do not like the new simplified Program.cs file with top statement . We had the top-level statement improve , and continues to be used for a template. We hope that most developers who like traditional methods can directly add additional methods themselves.
The following language features are used in the new template:
- Asynchronous Main
- Top-level statement
- Target-typed new expression
- global using directive
- File scope namespace
- Nullable reference type
We built all these features because we think they are better than the previous alternatives. Templates are the easiest and best way to guide new developers and new applications to the best mode. The C# design team firmly believes in using fewer lines and fewer characters to specify a given concept or operation, and reduce unnecessary repetition. This is what most of these new features support. The difference with Nullable is that it produces more reliable code. Every application or library that uses nullable is unlikely to crash in production. The software is so complicated that humans cannot see errors like a compiler.
A common theme of these features is that they reduce distractions and increase hints when you view the code in the code editor. Now, more important aspects will pop up. For example, if you see a using statement in a given file, it is a special statement that is required outside of the implicit set. You should be able to copy/paste code from one file to another without CTRL-. type to add the required namespace (at least not that much). If you see a nullable warning or error, you know that your code may be incorrect in some way. There are also benefits to removing the indentation. More code will be visible in the first dozen columns of the editor instead of just filling these columns with space characters. People can think of these characteristics as delivering a higher density of specificity and meaning to the eyes in the process of delivering information to the brain.
console template
Let's start with the console template. This is very small.
Program.cs:
// 查看 https://aka.ms/new-console-template 得到更多信息
Console.WriteLine("Hello, World!");
Project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Although the console template is much smaller than its .NET 5 counterpart, there is no reduction in functionality. You can also see that ImplicitUsings is now an optional feature and it is enabled in the template.
Web template
The web template is also very small.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
The webapi template is closer to a typical ASP.NET Core application. You will quickly notice that the separation between Program.cs and Startup.cs has been removed. Startup.cs is no longer needed.
Program.cs:
var builder = WebApplication.CreateBuilder(args);
// 添加 services to the container.
builder.Services.AddControllers();
// 学习更多关于configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
The project file of the webapi template is similar to the console.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.5" />
</ItemGroup>
</Project>
You can see in this example that the file scope namespace is used, included in WeatherForecast.cs:
namespace webapi;
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
The target type new is used with WeatherForecastController.cs:
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
In the mvc template, you can see the use of nullable annotations and expression body methods.
namespace webmvc.Models;
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
Windows Forms template
The Windows Forms template has also been updated. It includes most of the other improvements involved in other templates, even if it is not a top-level statement.
namespace winforms;
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
You can see that a single-line namespace statement is used, and because implicit use is enabled, there are no platform-level using statements.
The WPF template has not been updated as part of the release.
implicitly uses
Now I will show you the practical application of these features. Let's start with implicit usage. When enabled, will add its own set of implicit using statements each Sdk.
As mentioned earlier, Microsoft.NET.Sdk has added several global using statements.
If you disable this feature, you will see that the application no longer compiles because the System namespace is no longer declared (in this case).
PS C:Usersrichapp> type .app.csproj | findstr Implicit
<ImplicitUsings>disable</ImplicitUsings>
PS C:Usersrichapp> dotnet build
Microsoft (R) Build Engine version 17.0.0-preview-21501-01+bbcce1dff for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
C:UsersrichappProgram.cs(2,1): error CS0103: The name 'Console' does not exist in the current context [C:Usersrichappapp.csproj]
Build FAILED.
Another option is to use the global using feature, which allows you to use only the namespaces you want, as shown in the example below.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System" />
</ItemGroup>
</Project>
Now, build the code.
PS C:Usersrichapp> type .app.csproj | findstr Using
<ImplicitUsings>disable</ImplicitUsings>
<Using Include="System" />
PS C:Usersrichapp> dotnet build
Microsoft (R) Build Engine version 17.0.0-preview-21501-01+bbcce1dff for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
app -> C:UsersrichappbinDebugnet6.0app.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.80
This is not a recommended general mode, but it is a good choice for those who want the greatest degree of control. In most cases, we expect that developers will rely on the implicit use provided by the SDK and take advantage of the explicit global using of the namespace from their own code or commonly used NuGet packages.
I have updated Program.cs to demonstrate nullable reference types. The application calls the List<T> method and returns a T?, in this case a nullable string (string?)
List<string> greetings = new()
{
"Nice day, eh?"
};
string? hello = greetings.Find(x => x.EndsWith("!"));
string greeting = hello ?? "Hello world!";
Console.WriteLine($"There are {greeting.Length} characters in "{greeting}"");
If the line that defines the hello variable is not defined as var, string? or List< T >. Find returns null , then it cannot be compiled. If the nullable feature is not enabled, I might miss this issue, which will cause my code to crash due to NullReferenceException. That would be bad. I use ?? and empty coalescing operator on the next line. In most cases, these two lines of code will be merged into one line, as shown in the code below. Considering the APIs that return nullable reference types, I separate them (in this artificial example) so that you can see the string I use?
string greeting = greetings.Find(x =\> x.EndsWith("!"))??"Hello world!";
In this example, I merged everything into one line. I can now declare the variable as a string, because null has been adapted to the string after the ??. String? In this case, only the compiler can see it.
string[] args
Now, I will quickly solve most people's problems with top-level statements (including the args parameter). The args parameter is still available in the top-level statement. It's just not so obvious. Below is another program that demonstrates how to use it.
string greeting = args.Length > 0 ? string.Join(" ", args) : "Hello World!";
WriteLine($"There are {greeting.Length} characters in "{greeting}" in this {nameof(Program)}.");
It produces the following result.
PS C:\Users\rich\app> dotnet run
There are 12 characters in "Hello World!" in this Program.
PS C:\Users\rich\app> dotnet run Nice day, eh?
There are 13 characters in "Nice day, eh?" in this Program.
This application also demonstrates that the Program type is still defined. Program.Main is not.
By adding a global static using to my project file, I deleted the Console from the Console.WriteLine in Program.cs, as shown below.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="True"/>
</ItemGroup>
</Project>
defines the conventional method
We have heard feedback from some users who believe that the real method is better than the local function , especially for the Program class. You can use any model with top-level statements.
I keep the program unchanged, but switch all functions to static methods in the Program class and define them in some classes.
Program.cs.
WriteLine(GetTheGreeting(args));
Program.Foo.cs.
public partial class Program
{
public static string GetTheGreeting(string[] args)
{
string greeting = args.Length > 0 ? string.Join(" ", args) : "Hello World!";
return $"There are {greeting.Length} characters in "{greeting}" in this {nameof(Program)}.";
}
}
It produces the same result as the previous example. The file name of Program.Foo.cs is arbitrary. In fact, the same is true for Program.cs. You can give these files any name you like. The compiler will find them.
As mentioned earlier, when using top-level statements, the Program type must be in the top-level namespace.
macOS and Windows Arm64 update
In addition to good news, we also have some breakthrough changes to share. The project to support macOS and Windows arm64 has been basically completed. With the help of the macOS and Windows teams, we have been working on this for more than a year. At first, we thought that the project was just to support Arm64 on macOS, and Rosetta 2 would cover x64. Very simple, just like ISAs, right? not completely. As we dig deeper, we found that x64 + Arm64 coexistence is a larger task, mainly focused on CLI and installation procedures, including some where they need to agree. With RC2, we are delivering a build version of .NET to provide the best experience we can imagine.
I will quickly summarize our progress on macOS and Windows Arm64 machines:
- .NET 6 RC2 realizes Arm64 + x64 coexistence by installing Arm64 and x64 versions to different locations. So far, Arm64 and x64 builds cover each other, which led to general sadness.
- You need to uninstall all .NET versions and start from scratch (on macOS and Windows Arm64 machines) to adopt .NET 6 RC2+. This includes Arm64 and x64, .NET 6 and versions prior to .NET 6.
- Versions prior to .NET 6 are not yet ready for installation.
- CLI allows you to use Arm64 SDK for Arm64 and x64 development (assuming you have installed the required Arm64 and x64 runtimes). The reverse is also the same.
- We hope that people will only use the Arm64 SDK because it will have a better experience (native architecture performance; only one SDK needs to be maintained). We will continue to improve the product to make this model a simple choice for most developers.
- For SDK, we only support .NET 6+ on Arm64. Early SDK builds will be blocked .
- For runtime, we will support all supported versions, Arm64 and x64.
- .NET 6 RC2 provides a large amount of .NET 6 final experience for Arm64 (including x64 emulation).
- We hope to update the .NET Core 3.1 and .NET 5 runtimes to be consistent with .NET 6 RTM (in terms of time and technology). This is yet to be determined.
- The nightly build of RC2 is currently bad, so you need to wait a few more weeks until we actually release RC2 to try all of them.
- The .NET 5 SDK for Windows Arm64 will be withdrawn from support early with .NET 6 RTM.
We are also considering making some breakthrough changes to dotnet test in order to unify our views for architectural goals:
- [[Breaking change] For dotnet test, switch -a to alias –arch instead of –test-adapter-path](https://github.com/dotnet/sdk/issues/21389)
- [[Breaking change] For dotnet test, switch -r to alias –runtime instead of –results-dir](https://github.com/dotnet/sdk/issues/21952)
A large part of this project is to enable the x64 runtime through the Arm64 SDK. You can see this in the image below.
If you want to know more details, please check dotnet/sdk #21686 .
Summarize
Based on the similar features of C# 9, C# 10 provides significant improvements in simplicity and expressibility. In the past, people could reasonably laugh at C#, because just writing a single line of code required so much etiquette and knowledge of object-oriented concepts. Those days have passed, and the template reflects this. Part of the motivation for these changes is to make C# more attractive to new programmers and schools. These simplified changes fundamentally change what you need to start learning and proficiently using C#. In the new default form, it can be directly compared with other languages that similarly start with a single file source file.
We look forward to seeing other projects simplify their new user experience through top-level statements, global usage, logging, and many other modern features. There are many opportunities to create a simpler learning journey for open source projects and commercial products.
We encourage you to use .NET 6 RC2. We believe you will find it to be a reliable version. And the date of the global .NET Conf will November 9 , so .NET 6 release.
Thank you for being a .NET developer.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。