.NET 6 预览版 7 Released

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.NET 6 预览版 7 Released相关的知识,希望对你有一定的参考价值。

.NET 6 预览版 7 Released

Richard 2021 年 8 月 10 日

我们很高兴发布 .NET 6 Preview 7。这是我们进入(两个)发布候选 (RC) 期之前的最后一次预览版本。在我们放慢发布速度之前,团队经常加班夜战来保证最后一组功能。在这个版本中,您将看到对各种功能的最后一点润色,以及一次性推出的大型功能。从这一点来看,该团队将专注于将所有功能实现统一(高)质量,以便 .NET 6 为您的生产工作负载做好准备。

关于生产环境工作负载的话题,值得提醒大家的是,.NET 网站 和 Bing.com 自预览版 1 以来一直在 .NET 6 上运行。我们正在与各个团队(Microsoft 和其他团队)联系将.NET 6 RC 用于生产。如果您对此感兴趣并希望获得有关如何处理该问题的指导,请联系 dotnet@microsoft.com,我们总是乐于与早期采用者交流。

您可以下载适用于 Linux、macOS 和 Windows 的.NET 6 Preview 7。

  • 安装程序和二进制文件

  • 容器镜像

  • Linux 软件包

  • 发行说明

  • API差异

  • 已知问题

  • GitHub Issue 追踪

有关客户端和 Web 应用程序方案新增功能的更多详细信息,请参阅.NET MAUI和ASP.NET Core。

.NET 6 Preview 7 已经过测试,并且受Visual Studio 2022 Preview 3 支持。Visual Studio 2022 使您能够利用为 .NET 6 开发的 Visual Studio 工具,例如在 .NET MAUI 中进行开发、C# 应用程序的热重载、WebForms 的新 Web 实时预览以及 IDE 体验中的其他性能改进。Visual Studio Code也支持 .NET 6 。Visual Studio Code的 C# 扩展的最新版本已针对 .NET 6 Preview 7 进行了更新,并且包括对 C# 10 的支持。

查看新的对话帖子,就最新的 .NET 功能进行工程师对工程师的深入讨论。我们还发布了有关 C# 10 中的字符串插值和 .NET 6 中的 .NET 6 预览功能 – 通用数学的文章。

.NET SDK:现代化的 C# 项目模板

我们更新了 .NET SDK 模板以使用最新的 C# 语言功能和模式。我们已经有一段时间没有在新的语言功能方面重新审视模板了。是时候这样做了,我们将确保模板在未来使用新的和现代的功能。

新模板中使用了以下语言功能:

  • 顶级语句

  • 异步 Main 方法

  • 全局 using 指令(通过 SDK 驱动的默认值)

  • 文件范围的命名空间

  • 目标类型的新表达式

  • 可空引用类型

您可能想知道为什么我们通过模板启用某些功能,而不是在项目面向 .NET 6 时默认启用它们。您需要做一些工作来将应用程序升级到新版本的 .NET, 作为用于权衡改进平台的默认行为,这使我们可以改进产品,而不会随着时间的推移使项目文件复杂化。但是,该模型的某些功能可能会具有破坏性,例如可为空的引用类型。我们不想将这些功能与升级体验联系起来,但希望将选择权留给您,无论何时何地。模板是一个风险低得多的枢轴点,我们可以在那里为新代码通过项目模板启用这些功能,设置新的“良好默认模型”,而几乎没有下游后果。

控制台模板

Console模板演示了最大的变化。凭借顶级语句和全局 using 指令,它现在(有效的代码)是只有一行的。

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

同一模板的 .NET 5 版本包括几行熟悉的样式,新的模板只需要一行代码就可以提供以前实际代码所需的结构。

using System;

namespace Company.ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

console模板的项目文件也已更改,以启用可空引用类型功能,如下例所示

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

其他模板也支持可空性、隐式全局使用和文件范围的命名空间,包括 ASP.NET Core 和类库。

ASP.NET Web 模板

web模板也同样在使用相同的功能来减少代码行

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapGet("/", () => "Hello World!");

app.Run();

ASP.NET MVC 模板

mvc模板在结构上相似。在本例中,我们已将Program.csStartup.cs合并到一个文件 ( Program.cs) 中,从而进一步简化。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

模板兼容性

有关使用新模板的兼容性问题,请参阅以下文档。

  • 早期 .NET 版本不支持模板中的 C# 代码

  • 隐式命名空间导入

库:用于可空性信息的反射 API

可空引用类型是编写可靠代码的重要特性。它非常适合编写代码,但不适用于(直到现在)反射检查它。新的反射 API使您能够确定给定方法的参数和返回值的可空性性质。例如,这些新的 API 对基于反射的工具和序列化程序至关重要。

对于上下文,我们在 .NET 5 中向 .NET 库添加了可为空的注释(并在 .NET 6 中完成),并且正在对本版本的ASP.NET Core做同样的事情。我们还看到开发人员为他们的项目采用可空引用类型。

可空性信息使用自定义属性保存在元数据中。原则上,任何人都可以读取自定义属性,但是,这并不理想,因为使用编码是很重要的。

以下示例演示了将新 API 用于几个不同的场景。

获取顶级可空性信息

假设您正在实现一个序列化程序。使用这些新的 API,序列化程序可以检查给定的属性是否可以设置为null

private NullabilityInfoContext _nullabilityContext = new NullabilityInfoContext();

private void DeserializePropertyValue(PropertyInfo p, object instance, object? value)
{
    if (value is null)
    {
        var nullabilityInfo = _nullabilityContext.Create(p);
        if (nullabilityInfo.WriteState is not NullabilityState.Nullable)
        {
            throw new MySerializerException($"Property '{p.GetType().Name}.{p.Name}'' cannot be set to null.");
        }
    }

    p.SetValue(instance, value);
}

获取嵌套的可空性信息

可空性对可以(正式地)保存其他对象(如数组和元组)的对象进行了特殊处理。例如,您可以指定数组对象(作为变量,或作为类型成员签名的一部分)必须为非空,但元素可以为空,反之亦然。使用新的反射 API 可以检查这种额外级别的特异性,如以下示例所示。

class Data
{
    public string?[] ArrayField;
    public (string?, object) TupleField;
}
private void Print()
{
    Type type = typeof(Data);
    FieldInfo arrayField = type.GetField("ArrayField");
    FieldInfo tupleField = type.GetField("TupleField");

    NullabilityInfoContext context = new ();

    NullabilityInfo arrayInfo = context.Create(arrayField);
    Console.WriteLine(arrayInfo.ReadState);        // NotNull
    Console.WriteLine(arrayInfo.Element.State);    // Nullable

    NullabilityInfo tupleInfo = context.Create(tupleField);
    Console.WriteLine(tupleInfo.ReadState);                      // NotNull
    Console.WriteLine(tupleInfo.GenericTypeArguments [0].State); // Nullable
    Console.WriteLine(tupleInfo.GenericTypeArguments [1].State); // NotNull
}

库:ZipFile 遵循 Unix 文件权限

System.IO.Compression.ZipFile 类型现在在类Unix操作系统读取 zip 文件时,在创建和设置文件权限期间会捕获 Unix 文件权限,此更改允许通过 zip 文件来回传送可执行文件,这意味着您不再需要在解压缩 zip 存档后修改文件权限以使文件可执行。这也遵循了读/写权限,以及user/group/other 权限。

如果 zip 文档不包含文件权限(因为它是在 Windows 上创建的,或者使用未捕获权限的工具,如 .NET 的早期版本),则提取的文件将获得默认文件权限,就像任何其他文件一样新创建的文件。

Unix 文件权限也适用于其他 zip 存档工具,包括:

  • Info-ZIP

  • 7-Zip

.NET 7 早期功能预览:通用数学

对于 .NET 6,我们已经构建了将 API 标记为“预览中”的功能。这种新方法将使我们能够跨多个主要版本提供和使用预览功能。为了使用预览 API,项目需要明确选择使用预览功能。如果您在未明确选择的情况下使用预览功能,您将看到带有可操作消息的构建错误,从 .NET 6 RC1 开始。在以后的版本中,预览功能可能会以破坏性的方式发生变化。这就是让他们加入的原因。

我们在 .NET 6 中预览的其中一项功能是静态抽象接口成员。这些允许您在接口中定义静态抽象方法(包括运算符)。例如,现在可以实现代数泛型方法。对于某些人来说,此功能将是我们今年提供的绝对出色的改进,这可能会使Span<T> 之后的最重要的新的类型系统功能。

以下示例使用了一个 IEnumerable<T> 对象并且由于 T被限制为INumber<T>, 可能是INumber<int>,因此能够对所有值求和

public static T Sum<T>(IEnumerable<T> values)
    where T : INumber<T>
{
    T result = T.Zero;

    foreach (var value in values)
    {
        result += value;
    }

    return result;
}

这是有效的,因为 INumber<T> 定义了接口实现者必须满足的各种(静态)运算符重载。IAdditionOperators 也许是最简单的新接口来理解,这本身是从INumber 继承的。

这一切都由允许在接口中声明static abstract成员的新功能提供支持。这使接口能够公开运算符和其他静态方法,例如ParseCreate,以及由派生类型实现的那些。请参阅我们相关的博客文章了解更多详情!

这里提到的所有功能都是 .NET 6 的预览功能,不支持在生产中使用。我们将不胜感激您使用它们的反馈。我们打算在 .NET 7 中继续发展和改进通用数学功能以及支持它们的运行时和 C# 功能。我们希望对当前体验进行重大更改,这也是新 API 被标记为”在预览中”的部分原因。

库:NativeMemory API

我们增加了新的本机内存分配的API通过System.Runtime.InteropServices.NativeMemory暴露。这些 API 代表了mallocfreerealloccalloc C API 的等价物,还包括用于进行对齐分配的 API。

您可能想知道如何考虑这些 API。首先,它们是用于底层代码和算法的低级 API。应用程序开发人员很少会使用这些。考虑这些 API 的另一种方式类似于平台内在API,它们是用于芯片指令的低级 .NET API。这些 API 很相似,但为与内存相关的操作公开了低级 API。

库:System.Text.Json 序列化通知

System.Text.Json 序列化程序现在将通知作为(反)序列化操作的一部分公开。它们对于默认值和验证很有用。要使用它们,实现一个或多个接口IJsonOnDeserializedIJsonOnDeserializingIJsonOnSerializedIJsonOnSerializingSystem.Text.Json.Serialization 命名空间下。

这是一个在JsonSerializer.Serialize()JsonSerializer.Deserialize() 两者期间都进行验证并确保属性FirstName不是null的示例。

  public class Person : IJsonOnDeserialized, IJsonOnSerializing
  {
      public string FirstName{ get; set; }

      void IJsonOnDeserialized.OnDeserialized() => Validate(); // Call after deserialization
      void IJsonOnSerializing.OnSerializing() => Validate(); // Call before serialization

      private void Validate()
      {
          if (FirstName is null)
          {
              throw new InvalidOperationException("The 'FirstName' property cannot be 'null'.");
          }
      }
  }

在以前,您需要实现自定义转换器才能实现此功能。

库:System.Text.Json 序列化属性排序

我们还添加了控制属性序列化顺序的功能,使用 System.Text.Json.Serialization.JsonPropertyOrderAttribute. 一个整数指定顺序。较小的整数首先被序列化;没有属性的属性的默认排序值为 0。

这是一个指定 JSON 应按顺序序列化的示例:Id, City, FirstName, LastName

public class Person
{
    public string City { get; set; } // No order defined (has the default ordering value of 0)

    [JsonPropertyOrder(1)] // Serialize after other properties that have default ordering
    public string FirstName { get; set; }

    [JsonPropertyOrder(2)] // Serialize after FirstName
    public string LastName { get; set; }

    [JsonPropertyOrder(-1)] // Serialize before other properties that have default ordering
    public int Id { get; set; }
}

以前,序列化顺序是由反射顺序决定的,它既不是确定性的,也不是导致特定的所需顺序。

库:使用 System.Text.Json.Utf8JsonWriter“编写原始”JSON

在使用 Utf8JsonWriter编写 JSON 有效负载时,有时您需要集成“原始”JSON。

例如:

  • 我有一个有意在网络上写出的字节序列,并且我知道我在做什么(如下例所示)。

  • 我有一个 blob,我认为它代表 JSON 内容并且我想将其封装起来,我需要确保信封及其内部内容保持格式正确

JsonWriterOptions writerOptions = new() { WriteIndented = true, };

using MemoryStream ms = new();
using UtfJsonWriter writer = new(ms, writerOptions);

writer.WriteStartObject();
writer.WriteString("dataType", "CalculationResults");

writer.WriteStartArray("data");

foreach (CalculationResult result in results)
{
    writer.WriteStartObject();
    writer.WriteString("measurement", result.Measurement);

    writer.WritePropertyName("value");
    // Write raw JSON numeric value using FormatNumberValue (not defined in the example)
    byte[] formattedValue = FormatNumberValue(result.Value);
    writer.WriteRawValue(formattedValue, skipValidation: true);

    writer.WriteEndObject();
}

writer.WriteEndArray();
writer.WriteEndObject();

下面是对上面代码——特别是FormatNumberValue——正在做什么的描述。为了性能,System.Text.Json当数字为整数时省略小数点/值,例如1.0. 基本原理是写入更少的字节有利于性能。在某些情况下,保留十进制值可能很重要,因为消费者将没有小数的数字视为整数,否则视为双精度数。这种新的“原始值”模型使您可以随时随地进行控制。

库:同步流重载 JsonSerializer

我们添加了新的同步 API,JsonSerializer用于在流中序列化和反序列化 JSON 数据。您可以在以下示例中看到这一点。

using MemoryStream ms = GetMyStream();
MyPoco poco = JsonSerializer.Deserialize<MyPoco>(ms);

这些新的同步 API 包括通过接受JsonTypeInfo<T>JsonSerializerContext实例与新的System.Text.Json 源生成器兼容和可用的重载。

库:删除了System.Text.Json.Nodes.JsonNode 对 dynamic 的支持

JsonSerializer 中对 C# dynamic 类型的支持已被删除。我们dynamic在预览版 4 中添加了支持,但后来决定是一个糟糕的设计选择,包括使其成为JsonNode类型的必需依赖项。

此更改被认为是从 .NET 6 一个预览到另一个预览的重大更改,但不是从 .NET 5 到 6。

库:System.Diagnostics Propagators

在过去几年中,我们一直在改进对OpenTelemetry 的支持。实现强大支持的关键方面之一是确保需要参与遥测生产的所有组件以正确的格式生成网络标头。这真的很难做到,尤其是随着 OpenTelemetry 规范的变化。OpenTelemetry 定义了传播概念来帮助解决这种情况。我们正在采用传播来启用标头自定义的通用模型。

更广泛概念的背景:

  • OpenTelemetry规范——分布式跟踪数据结构的内存表示。

  • OpenTelemetry Span — 用于跟踪的构建块,由.NET 中的System.Diagnostics.Activity表示。

  • W3C TraceContext — 关于如何通过众所周知的 HTTP 标头传播这些分布式跟踪数据结构的规范。

以下代码演示了使用传播的一般方法。

DistributedContextPropagator propagator = DistributedContextPropagator.Current;
propagator.Inject(activity, carrier, (object theCarrier, string fieldName, string value) =>
{
   // Extract the context from the activity then inject it to the carrier.
});

您还可以选择使用不同的传播器。

// Set the current propagation behavior to not transmit any distributed context information in outbound network messages.
DistributedContextPropagator.Current = DistributedContextPropagator.CreateNoOutputPropagator();

DistributedContextPropagator抽象类确定是否和如何分配的上下文信息进行编码和解码,因为它穿过网络。编码可以通过任何支持键值字符串对的网络协议传输。DistributedContextPropagator将值注入到载体中并从载体中提取值作为键/值字符串对。通过添加对传播器的支持,我们启用了两件事:

  • 您不再需要使用W3C TraceContext标头。您可以编写自定义传播器(即,使用您自己的标头名称,包括根本不发送它们),而无需库 HttpClient、ASP.NET Core 具有此自定义格式的先验知识

  • 如果您使用自定义传输(例如,消息队列)实现库,则现在可以支持各种有线格式,只要您支持发送和接收文本映射(例如)Dictionary<string, string>

大多数应用程序代码不需要直接使用此功能,但是,如果您使用 OpenTelemetry,您很可能会在调用堆栈中看到它。如果关心跟踪和因果关系,一些库代码将可能参与此模型。

库:加密操作的简化调用模式

.NET 加密和解密例程是围绕流设计的,没有定义有效负载何时已经在内存中的真正概念。新的 Encrypt- 和 Decrypt- 方法SymmetricAlgorithm加速了内存中已经存在的情况,旨在为调用者和代码审查者提供清晰的信息。此外,它们支持从跨度读取和向跨度写入。

新的简化方法提供了一种使用加密 API 的直接方法:

private static byte[] Decrypt(byte[] key, byte[] iv, byte[] ciphertext)
{
    using (Aes aes = Aes.Create())
    {
        aes.Key = key;

        return aes.DecryptCbc(ciphertext, iv);
    }
}

使用新的 Encrypt- 和 Decrypt- 方法,仅使用来自 SymmetricAlgorithm 实例的 key 属性。新的 DecryptCbc 方法支持选择填充算法,但 PKCS#7 经常与 CBC 一起使用,因此它是默认参数。如果您喜欢清晰模式,只需指定它:

private static byte[] Decrypt(byte[] key, byte[] iv, byte[] ciphertext)
{
    using (Aes aes = Aes.Create())
    {
        aes.Key = key;

        return aes.DecryptCbc(ciphertext, iv, PaddingMode.PKCS7);
    }
}

您可以看到现有模式(使用 .NET 5)需要更多的管道才能获得相同的结果。

private static byte[] Decrypt(byte[] key, byte[] iv, byte[] ciphertext)
{
    using (Aes aes = Aes.Create())
    {
        aes.Key = key;
        aes.IV = iv;

        // These are the defaults, but let's set them anyways.
        aes.Padding = PaddingMode.PKCS7;
        aes.Mode = CipherMode.CBC;

        using (MemoryStream destination = new MemoryStream())
        using (ICryptoTransform transform = aes.CreateDecryptor())
        using (CryptoStream cryptoStream = new CryptoStream(destination, transform, CryptoStreamMode.Write))
        {
            cryptoStream.Write(ciphertext, 0, ciphertext.Length);
            cryptoStream.FlushFinalBlock();
            return destination.ToArray();
        }
    }
}

库:全球化不变模式下的完整案例映射支持

全球化不变模式使您能够消除应用程序对全球化数据和行为的依赖,以换取较小的应用程序(主要在 Linux 上)。我们改进了全球化不变模式以支持完整 Unicode 字符集的大小写映射。运营之前,该模式只支持ASCII字符范围比如 String.ToUpperString.ToLower和字符串比较,并与搜索IGNORECASE选项。

基于 Alpine 的 .NET 容器镜像是我们默认启用全球化环境模式的唯一环境。

运行时:W^X支持所有平台和架构

运行时现在有一种模式,在这种模式下,它不会同时创建或使用任何可写和可执行的内存页。所有可执行内存都映射为只读。此功能已在 macOS(适用于 Apple Silicon)上启用。在 Apple Silicon 机器上,同时可写和可执行的内存映射是被禁止的。

此功能现已在所有其他平台上启用和支持,作为可选体验。在这些平台上,可执行代码的生成/修改是通过单独的读写内存映射完成的。这对于 JIT 代码和运行时生成的帮助程序都是正确的。这些映射是在与可执行代码地址不同的虚拟内存地址处创建的,并且仅在执行写入时存在很短的时间。例如,JIT 现在将代码生成到暂存缓冲区中,在整个方法被 JIT 之后,使用单个内存复制函数调用将代码复制到可执行内存中。并且可写映射生命周期仅跨越内存复制的时间。

可以通过将环境变量设置DOTNET_EnableWriteXorExecute1. 此功能在 .NET 6 中是可选的,因为它具有启动回归(Apple Silicon 除外)。在我们的 ASP.Net 基准测试中,当使用 Ready To Run (R2R) 编译时,回归约为 10%。但是,在启用和不启用该功能的情况下,测量的稳态性能相同。对于启动性能不重要的应用程序,我们建议启用此功能以提高其提供的安全性。我们打算在 .NET 7 中解决性能回归问题,并在那时默认启用该功能。

运行时:CodeGen 变更日志

在预览版 7 中的代码生成中进行了以下更改。

社区 PR

以下 PR 均来自@SingleAccrtion:

  • 优化 32 位目标 runtime#53040CAST(int <- long)

  • 消除对小类型的链式转换 runtime#52561

  • 从除法变形中删除一些不需要的代码 runtime#53464

  • 修复长 muls 变形中的 CQ 回归和正确性错误 runtime#53566

  • 优化窄存储不要消除 FP 类型的强制转换 runtime#53667

  • 移动“不要零扩展 setcc”优化以降低 runtime#53778

  • 禁用实现定义的强制转换的折叠 runtime#53782

  • 为 VNF_MapStore 和 VNF_MapSelect 添加 args 描述 runtime#54108

  • 导入cgt.un(op, 0)NE(op, 0) runtime#54539

  • 使用本地断言道具在返回省略强制转换 runtime#55632

动态 PGO

以下 PR 支持动态 PGO 项目。

  • [JIT] 改进 inliner:新启发式,依赖 PGO 数据 runtime#52708

  • 内联:扩展配置调用站点的 IL 限制,允许内联交换机。runtime#55478

  • JIT:静态类推导失败时启用GDV。runtime#55660

LSRA

以下 PR 支持LRSA 项目。

  • 在定义时溢出单定义变量以避免进一步溢出 runtime#54345

  • 在 minopts 中将 vars 标记为 do not enreg。runtime#54998

循环优化

以下 PR 改进了循环优化。

  • 改进循环克隆,调试改进 runtime#55299

  • 支持使用结构索引表达式的数组克隆循环 runtime#55612

  • 将 RyuJIT 优化的最大循环从 16 增加到 64。runtime#55614

结构

以下 PR 改进了结构处理。

  • 在 win x64 上注册结构体。runtime#55045

  • Enreg Windows x86 struct。runtime#55535

  • 在所有平台上默认启用 StructEnreg。runtime#55558

  • 改进 TryTransformStoreObjAsStoreInd 优化。runtime#55727

优化

以下 PR 提供了一般优化。

  • 布尔逻辑中的“==0”优化 #13573 runtime#49548

  • 尾调用时允许隐式扩展runtime#54864

贡献者展示

我们即将——正如多次提到的那样——发布到最后。我们想花点时间展示一些做出重大贡献的社区贡献者。有很多人做出了重大贡献。以下人员是从团队中的一些人中被提名参加这次展示的。如果人们喜欢,我们可以继续这个展示部分。

文本是用贡献者自己的话写的。

Andrii Kurdiumov (@kant2002)

我是 Andrii Kurdiumov,住在哈萨克斯坦的阿拉木图。通过贸易,我致力于在企业中构建新产品。

我决定为 .NET 做出贡献,因为我看到了利用新的 MS 技术进入新市场的机会。Blazor WebAssembly 和 .NET on Raspberry 运行良好,但我担心这些技术会在极端或不寻常的要求下崩溃。所以我决定花一点时间来看看 NativeAOT 是否可以帮助我。到目前为止,我的贡献主要集中在 NativeAOT 项目上,甚至是 WinForms 项目。有一段时间我计划遵循这个方向。

这些就是我开始贡献的原因。我继续贡献的原因如下:我不断感受到 .NET 工作人员的支持,我知道他们在软件开发的广阔领域拥有丰富的经验。围绕 .NET 工作的人们非常关心高质量标准,这立即为周围的任何人定下了基调。我个人喜欢这种环境。

SingleAccretion

我是一个有抱负的年轻程序员,出人意料地来自俄罗斯。作为一个编写代码的人,我从 .NET 开始,逐渐从技术栈的较高层转到较低层,最终在编译器上工作,就在虚拟机的空白边缘:), . 这是一种相当迷人的活动,了解与 RyuJit 一样复杂和古老的系统,但这也是它独特的吸引力,我想,至少对于像我这样好奇的人来说。

然而,这不是我为 .NET 做出贡献的原因,毕竟我可以开始自己的分支。我认为可以公平地说,在这几个月里涉足了如此多的 GH 线程,在任何地方都无法看到人们对我们领域的问题有如此深刻和丰富的理解。成为这个社区的一员,并且能够对其中的问题进行推理,这是我真正珍惜的东西。

结语

我们正处于发行版的新时期,我们认为新功能和改进已经完成。干得漂亮,团队。这是另一季 .NET 预览的结束。

我们继续希望得到并依赖您的反馈。我们将把 .NET 6 的其余部分集中在回归(功能和性能)和新功能中发现的错误上。在大多数情况下,功能改进需要等待 .NET 7。请分享您的任何和所有反馈,我们很乐意对其进行分类。

感谢所有为 .NET 6 成为另一个伟大版本做出贡献的人。

感谢您成为 .NET 开发人员。

以上是关于.NET 6 预览版 7 Released的主要内容,如果未能解决你的问题,请参考以下文章

.NET 6 预览版 7 发布--(最后一个预览版)

.NET 6 预览版 7:新功能已完成 ,将专注于改进

译.NET 6 Preview 4 Released

官宣 .NET 6 预览版 6

更新丨.NET 7 预览版2 中的 ASP.NET Core

官宣.NET 7 预览版5