隐藏的 NET 9 宝石

2025-06-09

隐藏的 NET 9 宝石

介绍

当微软宣布 .NET Framework 的新版本时,都会有发行说明

发行说明并未涵盖所有新增功能。本文将通过 C# 示例介绍一些新功能。

可枚举.索引<T>

Enumerable.Index<T>返回一个将元素索引合并到元组中的可枚举值。

在使用 Index<T> 之前,有一种常规方法,即声明一个值为 -1 的 int 变量,并在 foreach 中增加该变量。

注意:
许多经验丰富的开发人员都使用这种方法,他们可能不太喜欢新的 Index 扩展方法,因为他们已经习惯了这种扩展方法。这种方法本身并没有问题。

示例 1

using static System.Globalization.DateTimeFormatInfo;
internal partial class Program
{
    static void Main(string[] args)
    {
        var index = -1;
        foreach (var month in Months)
        {
            ++index;
            Console.WriteLine($"{index,-5}{month}");
        }

        Console.ReadLine();

    }

    public static List<string> Months => CurrentInfo.MonthNames[..^1].ToList();
}
Enter fullscreen mode Exit fullscreen mode

上述代码的结果

另一种方法是编写扩展方法。以下是网络上众多方法之一。

示例 2

using static System.Globalization.DateTimeFormatInfo;
internal partial class Program
{
    static void Main(string[] args)
    {

        foreach (var (month, index) in Months.Index())
        {
            Console.WriteLine($"{index,-5}{month}");
        }

        Console.ReadLine();

    }

    public static List<string> Months => CurrentInfo.MonthNames[..^1].ToList();
}

public static class Extensions
{
    public static IEnumerable<(T item, int index)> Index<T>(this IEnumerable<T> sender)
        => sender.Select((item, index) => (item, index));
}
Enter fullscreen mode Exit fullscreen mode

上面的代码示例产生与上一个完全相同的输出。

示例 3

此示例是 NET9 原生的,不需要额外的扩展方法,在 .NET Core Framework 中使用Index 扩展。

internal partial class Program
{
    static void Main(string[] args)
    {

        foreach (var (month, index) in Months.Index())
        {
            Console.WriteLine($"{index,-5}{month}");
        }

        Console.ReadLine();

    }

    public static List<string> Months => CurrentInfo.MonthNames[..^1].ToList();
}
Enter fullscreen mode Exit fullscreen mode

上面的代码示例产生的输出与最后两个完全相同。

枚举.CountBy<TSource,TKey>

CountBy返回源序列中按键分组的元素数量。

CountBy 所需的代码比传统的 GroupBy 方法要少。

以下用于GroupByCountBy示例。

public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public Role Role { get; set; }
}

public enum Role
{
    Admin,
    Member,
    Guest
}
public static List<User> Users() =>
[
    new() { Id = 1, UserName = "John", Role = Role.Admin },
    new() { Id = 2, UserName = "Jane", Role = Role.Member },
    new() { Id = 3, UserName = "Joe", Role = Role.Guest },
    new() { Id = 4, UserName = "Alice", Role = Role.Admin },
    new() { Id = 5, UserName = "Bob", Role = Role.Member },
    new() { Id = 6, UserName = "Charlie", Role = Role.Guest },
    new() { Id = 7, UserName = "Dave", Role = Role.Admin },
    new() { Id = 8, UserName = "Eve", Role = Role.Member },
    new() { Id = 9, UserName = "Frank", Role = Role.Guest },
    new() { Id = 10, UserName = "Grace", Role = Role.Admin }
];
Enter fullscreen mode Exit fullscreen mode

任务是获取每个角色的数量。

GroupBy 示例

private void GroupByWithCount()
{
    var users = MockedData.Users();

    var groupedUsers = users.GroupBy(user => user.Role)
        .Select(group => new { Role = group.Key, Count = group.Count() });

    foreach (var group in groupedUsers)
    {
        Debug.WriteLine($"Role: {group.Role}, Count: {group.Count}");
    }
}
Enter fullscreen mode Exit fullscreen mode

CountBy 示例

private void CountByWithCount()
{
    var users = MockedData.Users();

    foreach (var roleCount in users.CountBy(user => user.Role))
    {
        Debug.WriteLine($"There are {roleCount.Value} users with the role {roleCount.Key}");
    }

}
Enter fullscreen mode Exit fullscreen mode

这两个例子,除了输出结果略有不同外,都还算可以接受,但 CountBy 乍一看更容易让人理解它的功能。有些人会更喜欢其中一个,毕竟有选择总是好的。

聚合依据

AggregateBy对序列应用累加器函数,按键对结果进行分组。

以下用于GroupByAggregateBy示例。

public class User
{
    public int Id { get; set; }
    public string UserName { get; set; }
    public Role Role { get; set; }
}

public enum Role
{
    Admin,
    Member,
    Guest
}

public class MockedData
{

    public static List<User> Users() =>
    [
        new() { Id = 1, UserName = "John", Role = Role.Admin },
        new() { Id = 2, UserName = "Jane", Role = Role.Member },
        new() { Id = 3, UserName = "Joe", Role = Role.Guest },
        new() { Id = 4, UserName = "Alice", Role = Role.Admin },
        new() { Id = 5, UserName = "Bob", Role = Role.Member },
        new() { Id = 6, UserName = "Charlie", Role = Role.Guest },
        new() { Id = 7, UserName = "Dave", Role = Role.Admin },
        new() { Id = 8, UserName = "Eve", Role = Role.Member },
        new() { Id = 9, UserName = "Frank", Role = Role.Guest },
        new() { Id = 10, UserName = "Grace", Role = Role.Admin }
    ];

    public static (string name, string department, int vacationDaysLeft)[] Employees =
    [
        ("John Doe", "IT", 12),
        ("Eve Peterson", "Marketing", 18),
        ("John Smith", "IT", 28),
        ("Grace Johnson", "HR", 17),
        ("Nick Carson", "Marketing", 5),
        ("Grace Morgan", "HR", 9)
    ];

}
Enter fullscreen mode Exit fullscreen mode

GroupBy 示例

private static void GroupByAggregateBySample()
{
    var kvp = MockedData.Employees
        .GroupBy(emp => emp.department)
        .Select(group => new KeyValuePair<string, int>(group.Key, group.Sum(emp 
            => emp.vacationDaysLeft)));

    foreach (var (key, value) in kvp)
    {
        Debug.WriteLine($"Department {key,-15} has a total of {value} vacation days left.");
    }
}
Enter fullscreen mode Exit fullscreen mode

AggregateBy 示例

private static void AggregateBySample()
{
    var kvp = MockedData.Employees
        .AggregateBy(emp => emp.department, 0, (acc, emp)
            => acc + emp.vacationDaysLeft);

    foreach (var (key, value) in kvp)
    {
        Debug.WriteLine($"Department {key,-15} has a total of {value} vacation days left.");
    }
}
Enter fullscreen mode Exit fullscreen mode

以上两者的输出相同。

Department IT              has a total of 40 vacation days left.
Department Marketing       has a total of 23 vacation days left.
Department HR              has a total of 26 vacation days left.
Enter fullscreen mode Exit fullscreen mode

UUID v7 生成

在 NET 9 之前,需要以下 NuGet 包UUIDNext来创建 UUID/GUID。

使用 NET 9。

//Creates a new Guid according to RFC 9562, following the Version 7 format.
var item1 = Guid.CreateVersion7();

//Creates a new Guid according to RFC 9562, following the Version 7 format with DateTimeOffset
var item2 = Guid.CreateVersion7(TimeProvider.System.GetUtcNow());

Debug.WriteLine(item1);
Debug.WriteLine(item2);
Enter fullscreen mode Exit fullscreen mode

概括

NET 9 推出了几项新功能,这些功能在 Visual Studio 2022 的 17.12 版本中没有出现,可能会对开发人员有益。

源代码是在 Windows 窗体项目中完成的,这使得所有呈现的功能都可以在一个项目而不是多个项目中完成。

源代码

鏂囩珷鏉ユ簮锛�https://dev.to/karenpayneoregon/hidden-net-9-gems-3pb4
PREV
为什么干净的代码是富有同情心的代码
NEXT
使用 C# 简单介绍通用存储库模式