.NET 9/10 重磅升级:揭秘七大变革性新特性

作者:微信公众号:【架构师老卢】
8-2 8:28
16

.NET 9/10 是一个重大版本更新,带来了广泛的增强功能,从性能优化到旨在简化开发并改进跨平台和云原生应用程序的新特性。本文将探讨 .NET 9/10 中一些最重要的更新,包括 C# 的变更、性能改进、增强的工具链等等。

1. ASP.NET Core 改进 ASP.NET Core 在 .NET 9/10 中持续演进,进行了多项关键改进,旨在使 Web 开发更轻松、更高效。

Minimal API 增强

  • 数据绑定 (Data Binding):.NET 9/10 增强了对更复杂数据绑定场景的支持,使得处理更高级的输入模型和验证更加容易。
  • 验证 (Validation): 改进了如何为传入模型实施验证的方式,允许你编写更清晰、更健壮的验证逻辑。

示例:

app.MapPost("/register", (UserModel user) =>
{
    if (string.IsNullOrEmpty(user.Name))
    {
        return Results.BadRequest("Name is required.");
    }
    return Results.Ok("User registered successfully!");
});

public record UserModel(string Name, string Email);

说明: 该示例展示了 Minimal API 如何让你用最少的代码处理 POST 请求。借助 .NET 9/10 的增强功能,可以支持更复杂的场景,包括更好的数据绑定和验证,而无需复杂的中间件或控制器。 验证可以直接在终结点内执行,数据绑定也更加灵活,支持复杂模型以及像 [Required] 这样的特性或自定义验证逻辑。

2. .NET 9/10 中的 Params 集合改进 在 .NET 9/10 中,params 关键字已被扩展以支持更广泛的集合类型,包括使用集合表达式(在 .NET 8 中引入)创建的集合。这一增强使处理可变参数变得更加灵活和强大,超越了传统的数组,并提供了与现代集合类型更好的集成。

  • 支持更广泛的集合: 虽然 params 关键字传统上只支持数组,但 .NET 9 现在允许它接受各种集合类型,包括 List<T>IEnumerable<T> 以及使用集合表达式创建的集合(如 new[] {} 语法或 LINQ 查询)。

用法示例: 以下示例演示了在 .NET 9/10 中如何将集合表达式与 params 关键字结合使用:

public class MathOperations
{
    public int AddNumbers(params int[] numbers)
    {
        return numbers.Sum();
    }
}

// 使用集合表达式 (从 .NET 8 开始)
MathOperations operations = new MathOperations();
int result = operations.AddNumbers(1, 2, 3, 4, 5); // 传递传统数组
// 使用 List ( .NET 9/10 新增)
List<int> numberList = new List<int> { 1, 2, 3, 4, 5 };
int resultFromList = operations.AddNumbers(numberList);  // 无需 ToArray()

// 使用 LINQ 集合表达式 ( .NET 9/10 新增)
int resultFromLinq =
        operations.AddNumbers(new[] { 1, 2, 3 }.Concat(new[] { 4, 5 }));

Console.WriteLine(result);  // 输出: 15
Console.WriteLine(resultFromList);  // 输出: 15
Console.WriteLine(resultFromLinq);  // 输出: 15

在此示例中:

  • 在 .NET 9/10 中,AddNumbers 可以与传统数组以及更动态的集合(如 List<int> 和 LINQ 表达式)无缝协作。你现在可以直接将 List<T>IEnumerable<T> 传递给使用 params 关键字的方法,而无需将它们转换为数组(ToArray())。
  • 对于大多数集合类型,在 .NET 9/10 及更高版本中,严格来说不再需要 .ToArray() 转换,但在处理本身未实现 IEnumerable<T> 的类型时仍然需要。

意义: 通过能够直接使用 List<T>IEnumerable<T> 或 LINQ 结果等集合作为 params 参数,.NET 9/10 使得无需显式将集合转换为数组即可将动态集合传递给方法变得更加容易。这一改进消除了将集合转换为数组的冗余代码需求,简化了在更复杂场景中使用 params 的过程。

3. .NET MAUI:轻松实现跨平台开发 .NET MAUI (多平台应用 UI) 通过允许你编写可在 Android、iOS、macOS 和 Windows 上运行的单一代码库,简化了跨平台应用程序的开发。

增强的性能和 Linux 支持 .NET 9/10 提高了 MAUI 应用程序的性能,并扩展了平台支持,现在包括 Linux

示例:

using Microsoft.Maui.Controls;

class MainPage : ContentPage
{
    public MainPage()
    {
        Content = new Label
        {
            Text = "Hello, .NET MAUI!",
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.Center,
        };
    }
}

说明: 此更新使 .NET MAUI 更接近成为一个真正的跨平台解决方案,简化了需要在多个平台上运行且对代码库改动最少的应用程序的开发。

4. SwaggerUI 被移除,由新的 OpenAPI 文档系统取代 Microsoft 已从 Web 项目模板中移除 SwaggerUI,并引入了一个更现代化、集成化的 OpenAPI 文档系统。这个新系统允许开发者以更精简高效的方式记录、测试和可视化他们的 API。现在,你可以轻松定制每个 API 终结点的文档,包括详细的参数描述、响应类型和错误代码。它旨在提供更快的性能和与 .NET 应用程序更好的集成,并经过优化,即使在更大、更复杂的 API 项目中也能高效工作。

新的 OpenAPI 支持 新的 OpenAPI 系统(由 Microsoft.AspNetCore.OpenApi 命名空间提供)简化了 API 文档生成并增强了性能。这个新工具并非直接替代 SwaggerUI 的完全相同功能,但它为记录 API 提供了强大的替代方案,包括更好的集成和对新用例的支持。

如何实现新的 OpenAPI 文档 过渡到新的 OpenAPI 文档系统非常简单。以下是如何在你的 .NET 9/10 项目中开始使用它:

添加 OpenAPI NuGet 包 首先,你需要将 Microsoft.AspNetCore.OpenApi 包添加到你的项目中。你可以通过 NuGet 或使用 .NET CLI 来完成。 使用 .NET CLI:

dotnet add package Microsoft.AspNetCore.OpenApi

在 Program.cs 中配置 OpenAPI 安装包后,你需要修改 Program.cs 文件以启用 OpenAPI 支持。添加以下代码行来配置 OpenAPI 系统。

示例:

var builder = WebApplication.CreateBuilder(args);

// 添加 OpenAPI 服务
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();  // 添加 OpenAPI 文档服务

var app = builder.Build();

// 在开发环境下启用 OpenAPI 文档
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(); // 使用新版 UI
}

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

app.Run();

访问 OpenAPI 文档 现在,你的 OpenAPI 文档默认将在 /swagger URL 下提供,取代了传统的 SwaggerUI。这为你提供了 API 终结点、响应和潜在错误的可视化表示,使在开发过程中测试和验证 API 变得更加容易。

OpenAPI 集成示例 这是一个演示如何定义 API 终结点并为其生成 OpenAPI 文档的基本示例。

用于定义带 OpenAPI 文档的 API 终结点的 C# 代码:

app.MapGet("/api/products/{id}", (int id) =>
{
    var product = new Product { Id = id, Name = "Laptop", Price = 999.99 };
    return Results.Ok(product);
})
.WithName("GetProductById") // 为终结点分配可读名称,将出现在 OpenAPI 文档中
.WithOpenApi();  // 为终结点添加 OpenAPI 文档

说明:

  • .WithOpenApi() 方法向终结点添加 OpenAPI 文档。
  • .WithName() 方法为终结点分配一个可读的名称,该名称将出现在 OpenAPI 文档中。

5. 新的 LINQ 方法 新增了三个方法:CountByAggregateByIndex。这些方法无疑是 .NET 9/10 在数据操作和 LINQ 功能方面的改进的一部分。引入这些方法是为了简化和增强常见的数据操作,使它们更具表达力和效率。

以下是每个方法的解析:

1. CountBy CountBy 方法允许你计算符合特定条件或键的元素的出现次数,这是数据处理中的常见模式。它本质上是以更简洁的形式结合了 GroupByCount

示例:

var data = new[] { "apple", "banana", "apple", "orange", "banana", "banana" };
var countByFruit = data.CountBy(fruit => fruit);

foreach (var group in countByFruit)
{
    Console.WriteLine($"{group.Key}: {group.Count}");
}

输出:

apple: 2
banana: 3
orange: 1

2. AggregateBy AggregateBy 方法允许你对按键分组的元素执行聚合操作,类似于 GroupBy,但它允许你在操作中指定聚合操作(例如求和、求平均值等),从而简化代码。

示例:

var data = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var sumByEvenOdd = data.AggregateBy(x => x % 2 == 0, x => x); // 按奇偶分组并求和

foreach (var group in sumByEvenOdd)
{
    Console.WriteLine($"{(group.Key ? "Even" : "Odd")}: {group.Sum()}");
}

输出:

Odd: 25
Even: 20

3. Index Index 方法提供了一种直接映射序列中元素索引的方式,这对于索引本身很重要的操作(例如按索引检索元素或执行依赖于元素位置的操作)特别有用。

示例:

var data = new[] { "apple", "banana", "orange" };
var indexedData = data.Index(); // 获取带索引的元素集合

foreach (var (index, value) in indexedData)
{
    Console.WriteLine($"{index}: {value}");
}

输出:

0: apple
1: banana
2: orange

总结:

  • CountBy:简化按指定条件或键对元素进行计数。
  • AggregateBy:将分组和聚合结合到一个更简洁的方法中。
  • Index:提供了一种同时处理元素及其在集合中索引的方式。

6. System.Text.Json 序列化程序改进 .NET 9/10 对 JSON 序列化程序(System.Text.Json)进行了显著改进,为处理 JSON 数据的开发者提升了性能和易用性。这些变更旨在简化序列化和反序列化过程,使其更快、更高效,同时提供对 .NET 应用程序中如何处理 JSON 数据的更大灵活性和控制。这些优化源于改进的算法和更好的内存管理,减少了在 .NET 对象与 JSON 之间转换所涉及的开销。

示例: 以下示例展示了如何使用改进后的 JSON 序列化程序进行数据的序列化和反序列化:

using System.Text.Json;

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
}
// 将产品对象序列化为 JSON
Product product = new Product { Id = 1, Name = "Laptop", Price = 999.99 };
string jsonString = JsonSerializer.Serialize(product);
// 将 JSON 反序列化回产品对象
Product deserializedProduct = JsonSerializer.Deserialize<Product>(jsonString);

在 .NET 9/10 中,JsonSerializer 针对速度进行了优化,减少了序列化时间,这在处理大型对象集合时尤其有益。

除了性能改进,.NET 9/10 的 JSON 序列化程序还引入了更简单、更直观的 API。改进后的 API 允许开发者轻松配置选项,如自定义转换器、属性命名策略等,而无需编写复杂的代码。

示例:

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
};

string jsonString = JsonSerializer.Serialize(product, options);

在此示例中,任何值为 null 的属性将从生成的 JSON 字符串中省略,这有助于减少在网络传输大型对象时的有效负载大小并提高性能。

自定义转换器 .NET 9/10 还为更高级的场景提供了一种更简单的方式来实现和使用自定义转换器。如果你需要以特定方式序列化或反序列化某个类型,你可以实现一个自定义转换器并将其全局或局部应用。

示例: 以下是如何创建和应用自定义转换器:

public class PriceConverter : JsonConverter<double>
{
    public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.GetDouble();
    }

    public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
    {
        writer.WriteNumberValue(value * 1.2);  // 例如,添加税费
    }
}
// 用法
var options = new JsonSerializerOptions();
options.Converters.Add(new PriceConverter());
string jsonString = JsonSerializer.Serialize(product, options);

这个自定义转换器可以在将产品价格序列化为 JSON 时,为其添加税费(示例目的)。

7. .NET 9/10 为何重要 .NET 9/10 充满了新特性,使开发者能够创建更快、更高效的应用程序。从性能优化到 C# 13 中更强大的语言特性,再到现代化的跨平台开发工具链(如增强的 .NET MAUI)、更高效的 API 文档(OpenAPI)、强大的新数据操作能力(LINQ)以及一流的 JSON 序列化支持,.NET 9 将自己定位为现代应用程序开发不可或缺的工具。

相关留言评论
昵称:
邮箱:
阅读排行