首页 > 编程语言 >.NET 9 优化,抢先体验 C# 13 新特性

.NET 9 优化,抢先体验 C# 13 新特性

时间:2024-08-20 10:26:09浏览次数:11  
标签:13 C# 方法 使用 NET ref public

前言

微软即将在 2024年11月12日发布 .NET 9 的最终版本,而08月09日发布的.NET 9 Preview 7 是最终发布前的最后一个预览版。这个版本将与.NET Conf 2024一同亮相,并已与 Visual Studio 2022 17.12 预览版1一同发布,可以直接通过Visual Studio安装。同时Visual Studio Code 和 C# Dev Kit 扩展也支持.NET 9。

C# 13 作为 .NET 9 的一部分,将带来一系列新特性,提升开发灵活性和性能,让编程体验更加流畅。尽管C# 13 尚未正式发布,但我们可以在 .NET 9 Preview 7 中尝试这些新特性,需要下载最新的 Visual Studio 2022 17.11 预览版。

注意:目前 C# 13 尚未正式发布,因此功能细节可能会有所调整。

新特性

1、params 集合增强,以提高灵活性

在 C# 13 中,params关键字的使用已经扩展到不仅仅是数组,还可以应用于任何可识别的集合类型,包括System.Span<T>、System.ReadOnlySpan<T>和实现了System.Collections.Generic.IEnumerable<T>的类型。

2、锁对象

.NET 9 运行时引入了System.Threading.Lock类型,提供了改进的线程同步机制。Lock类型通过其 API 支持更高效的线程同步操作,例如Lock.EnterScope()方法可以进入一个独占作用域

3、索引器改进

索引器的使用变得更加直观和灵活,能够更高效地操作集合。

4、转义序列\e

使用 \e 的好处是它可以避免与十六进制转义序列混淆。

5、部分属性

部分属性的引入使得属性的定义和实现可以分布在不同的文件中,提高了代码的组织性和可维护性。

6、方法组自然类型改进

方法组的自然类型得到了改进,使得调用变得更简单,减少了不必要的转换。

7、ref 和 unsafe 在 async 方法和迭代器中的使用

现在 async 方法和迭代器可以使用ref变量和不安全代码,可以在更多情况下使用这些特性,尽管仍然有一些限制。

8、关于扩展类型(Extension Types)的更新

C# 13 中一个非常重大的特性,它允许向现有类添加新的方法、属性、甚至静态成员,而无需修改原始类代码。

9、LINQ 新方法

新增了CountBy和AggregateBy方法,允许按键聚合状态而无需通过GroupBy分配中间分组,这为数据聚合提供了更灵活的方式

10、Foreach 支持 Index

引入了Index<TSource>(IEnumerable<TSource>),使得在 foreach 循环中可以快速提取可枚举项的索引

11、序列化改进

System.Text.Json在 .NET 9 中进行了改进,提供了新的选项用于 JSON 序列化,并引入了 JsonSerializerOptions.Web 单例,简化了使用 Web 默认值进行序列化的过程。

12、性能改进

.NET 9 在异常处理、环路性能、动态 PGO(按配置文件优化)、RyuJIT 编译器以及 Arm64 指令集支持方面进行了优化,显著提升了应用程序的性能。

Params 集合

params关键字允许方法接受一个参数列表,这个列表可以是任何实现了IEnumerable<T>接口的集合类型。

意味着可以使用方法参数来传递数组、列表、元组等集合,而不必显式地创建集合实例。

以下是一个使用 params关键字的简单示例:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    // 这个方法可以接受任意数量的字符串参数
    public static void PrintNames(params string[] names)
    {
        Console.WriteLine("Names provided:");
        foreach (var name in names)
        {
            Console.WriteLine(name);
        }
    }

    public static void Main()
    {
        // 直接传递字符串参数
        PrintNames("Alice", "Bob", "Charlie");

        // 使用数组
        string[] namesArray = new string[] { "Dave", "Eve", "Frank" };
        PrintNames(namesArray);

        // 使用列表
        List<string> namesList = new List<string> { "Grace", "Heidi", "Ivan" };
        PrintNames(namesList);

        // 使用 LINQ 表达式
        var query = from person in new List<Person> {
            new Person("Judy", "Walker"),
            new Person("Kevin", "Smith")
        }
        select person.FirstName;
        PrintNames(query);

        // 使用从集合中选择的属性
        var persons = new List<Person>
        {
            new Person("Leonard", "Nimoy"),
            new Person("Morgan", "Freeman")
        };
        PrintNames(from p in persons select p.FirstName);
    }
}

public class Person
{
    public string FirstName { get; }
    public string LastName { get; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
}

在这个示例中,PrintNames方法使用params关键字来接受任意数量的字符串参数。可以使用多种方式调用这个方法:

  • 直接传递字符串字面量。

  • 传递一个字符串数组。

  • 传递一个字符串列表。

  • 使用 LINQ 查询来传递查询结果。

  • 使用 LINQ 从Person对象的集合中选择FirstName属性。

这个示例展示了params集合的灵活性,允许以多种不同的集合类型传递参数,而方法内部的实现保持不变。

锁对象

众所周知,lock 是一种功能,通过监视器用于线程同步。

object lockObject = new object();
lock (lockObject)
{
    // 关键区
}

但是,这个功能的开销其实很大,会影响性能。为了解决这个问题,C# 13 实现了锁对象。要使用此功能,只需用 System.Threading.Lock 替换被锁定的对象即可:

using System.Threading;

Lock lockObject = new Lock();
lock (lockObject)
{
    // 关键区
}

这样就可以轻松提高性能了。

索引器改进

对索引器的改进,其中包括在对象初始化器中使用”尾部索引"(也称为“从末尾开始的索引”)的能力。

这种索引方式允许从集合的末尾开始计数,使用 ^ 符号来指定元素的位置。

以下是 C# 13 中索引器改进的示例:

using System;

public class Demo
{
    public static void Main()
    {
        // 定义一个可索引的类型
        var data = new IndexedData
        {
            // 使用传统的索引器初始化
            Items = { [2] = "Second", [3] = "Third" },

            // 使用尾部索引初始化
            [^1] = "First", // 从末尾开始的第一个元素
            [^2] = "Fourth" // 从末尾开始的第二个元素
        };

        // 打印初始化后的数据
        for (int i = 0; i < data.Items.Length; i++)
        {
            Console.WriteLine($"Index {i}: {data.Items[i]}");
        }
    }
}

public class IndexedData
{
    public string[] Items { get; set; } = new string[5];
}

在这个示例中,IndexedData 类有一个名为 Items 的字符串数组属性。

在初始化 data 对象时,我们使用了两种索引方式:

  • 传统的索引器,通过指定索引位置(例如 [2] 和 [3])来初始化数组元素。

  • 尾部索引器,使用 ^ 符号后跟数字来指定从数组末尾开始的位置(例如 1 和 2)。

当运行Main方法时,它将打印出数组中每个元素的索引和值,包括使用尾部索引初始化的元素。

输出结果将是:

Index 0: 
Index 1: 
Index 2: Second
Index 3: Third
Index 4: First

请注意,尾部索引 1 被分配给了数组的最后一个位置(索引4),而 2被分配给了倒数第二个位置(索引3),这是因为它们是从末尾开始计数的。这种特性在初始化数组或集合时特别有用,尤其是当你需要在已知末尾元素的情况下进行初始化时。 转义序列 \e在 Unicode 字符串中,可以使用\e 来代表 ESCAPE 字符,它等同于传统的\u001b 或\x1b。

  • \u001b 是一个 Unicode 转义序列,其中 \u 后跟的四位十六进制数代表一个 Unicode 点。

  • \x1b 是一个十六进制转义序列,\x 后面跟的两位十六进制数代表一个 ASCII 字符。

  • \e 直接表示 ESCAPE 字符,它避免了可能的混淆。

推荐使用 \e 是因为它提供了一种清晰无歧义的方式来表示 ESCAPE 字符。例如,\x1b 后如果紧跟数字可能会造成混淆,如 \x1b3 可能被误解为单一的转义序列。使用 \e 就可以清楚地表达 ESCAPE 字符,避免了这种混淆。

部分属性

在 C# 13 之前,属性不支持使用partial修饰符,这意味着属性的声明和实现必须在同一个位置完成。这在自动生成代码或分离关注点时可能会带来限制。

C# 13 改进了这一点,允许属性跨越多个部分进行声明和实现。特性特别适用于与源代码生成器等工具结合使用的场景,可以更灵活地生成和管理属性代码。

以下是 C# 13 中属性支持partial的示例:

public class DemoModel
{
    //声明部分属性
    public partial int MyProperty { get; set; }
}

public class DemoModel
{
    // 部分属性的实现
    public partial int MyProperty
    {
        get { return GetValue(); }
        set { SetValue(value);   }
    }
}

这种方式可以专注于属性的业务逻辑部分,而将具体的实现细节留给自动化工具处理,从而提高开发效率并减少重复性编码工作。

方法组自然类型

方法组的自然类型改进允许编译器更精确地确定方法的自然类型,特别是在重载解析时。这意味着编译器可以更有效地识别应该使用哪个重载版本,尤其是在涉及委托和方法组的情况下。

以下是一个示例,展示了 C# 13 中方法组自然类型的改进:

using System;

public class Program
{
    public static void Main()
    {
        // 声明一个委托类型,它指向一个接受 Action 作为参数的方法
        Action<string> action = PrintMessage;

        // 调用 PrintMessage 方法,使用方法组作为参数
        action("Hello, World!");
    }

    // 这是原始的重载版本
    public static void PrintMessage(string message)
    {
        Console.WriteLine($"Original: {message}");
    }
    // C# 13 允许更精确的自然类型推断
    public static void PrintMessage(Action<string> messagePrinter, string message)
    {
        messagePrinter(message);
        Console.WriteLine("Improved natural type inference in C# 13.");
    }
}

在这个示例中,PrintMessage方法有两个重载。第一个重载接受一个string参数,而第二个重载接受一个Action<string>和一个string参数。

在 C# 13 之前,如果尝试使用方法组调用action委托,编译器可能会在重载解析时产生模糊性,因为它需要确定使用哪个重载。

C# 13 中的方法组自然类型改进允许编译器更准确地推断出应该使用第一个 PrintMessage 重载,因为它更匹配传递的参数类型(一个字符串)。第二个重载虽然也能接受字符串,但它期望的是一个Action<string>类型的参数,这在方法组调用中是不匹配的。

请注意,这个示例仅用于说明 C# 13 中方法组自然类型改进的概念。在实际代码中,可能需要根据具体情况调整方法签名和调用方式。

ref 和 unsafe 在 async 方法和迭代器中的使用

在 C# 13 之前,ref 和 unsafe 关键字在异步方法(使用 async和 await 修饰的方法)和迭代器中有一些限制。

然而,C# 13 放宽了这些限制,可以在这些上下文中使用 ref 和 unsafe。

以下是一些示例,展示在 C# 13 中如何在异步方法和迭代器中使用 ref 和 unsafe:

1、在异步方法中使用ref

async Task RefInAsyncMethod()
{
    int value = 0;
    await Task.Yield();
    ref int local = ref ModifyValue(ref value);
    local++; // 修改原始变量的值
    Console.WriteLine(value); // 输出修改后的值
}

ref int ModifyValue(ref int x)
{
    return ref x;
}

在这个示例中,ModifyValue方法返回对传入引用的引用。在异步方法RefInAsyncMethod中,我们使用await Task.Yield();来切换到另一个上下文,然后通过ref返回的引用来修改原始变量的值。

2、在迭代器中使用ref

IEnumerable<int> GetNumbers()
{
    int number = 0;
    yield return number; // 返回第一个值
    number++;            // 修改状态
    yield return number; // 返回修改后的值
}

// 使用迭代器
foreach (int num in GetNumbers())
{
    Console.WriteLine(num);
}

在这个示例中,迭代器GetNumbers使用yield return来返回序列中的值。

在两次yield调用之间,迭代器的状态(number 变量)被保持,允许在第二次迭代时返回修改后的值。

3、在异步方法中使用unsafe

async Task UnsafeInAsyncMethod()
{
    unsafe
    {
        int* p = stackalloc int[10];
        for (int i = 0; i < 10; i++)
        {
            p[i] = i;
        }

        await Task.Yield(); // 切换上下文

        // 继续使用 p
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(p[i]);
        }
    }
}

在这个示例中,unsafe上下文被用在异步方法UnsafeInAsyncMethod中。我们使用stackalloc在栈上分配内存,并在await之前和之后访问这个内存。

这展示了即使在异步方法中,也可以执行不安全操作。

4、注意事项

  • 在异步方法中使用 ref和 unsafe需要谨慎,因为await会导致方法的执行上下文被挂起和恢复,这可能会影响对 ref 局部变量和 unsafe 代码的预期行为。

  • 确保在使用 ref 和 unsafe代码时,遵守 C# 的安全和并发规则。

C# 13 的这些改进提供了更大的灵活性,可以在异步编程和迭代器中使用ref和unsafe代码,但同时也需要更多的注意来确保代码的正确性和安全性。

总结

C# 13 带来的新特性和改进,如扩展类型的灵活性、params 关键字的增强、在异步方法中使用ref 和unsafe的能力,以及对序列化性能的优化等,都极大地提升了我们开发效率,解决了很多实际开发中遇到的问题。

对 .NET 9 和 C# 13 的正式发布充满期待,相信将为社区带来更加强大和便捷的工具,进一步推动技术的更新和发展。下载最新的 Visual Studio 2022-17.11 预览版,可以亲自体验这些新特性。

下载地址

下载.NET 9.0

Visual Studio 2022 预览版

参考链接

《C# 13: Explore the latest preview features》

《提高 C# 的生产力:C# 13 更新完全指南》

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

标签:13,C#,方法,使用,NET,ref,public
From: https://www.cnblogs.com/1312mn/p/18367817

相关文章

  • C语言 函数
    数组概念C语言中得函数就是一个完成某项特定的任务的一小段代码。这段代码是有特殊的写法和调试方式的。C语言的程序是由无数个小的函数组成的C语言中我们会用到两种函数:库函数自定义函数库函数1.标准库和头文件C语言中是不会提供任何函数的,C语言的国际标准(ANSIC)规定了......
  • CSS学习笔记
    CSS(CascadingStyleSheet)层叠级联样式表CSS:表现(美化网页)字体、颜色、边距、高度、宽度、背景图片、网页定位、网页浮动……建议HTML和CSS分开写 CSS的优势:内容和表现分离网页结构表现统一,可以实现复用样式十分丰富建议使用独立HTML的CSS文件利用SEO,容易被搜索引擎收......
  • 免费Excel工作表同类数据合并工具
       下载地址:https://pan.quark.cn/s/81b1aeb45e4c在Excel表格中,手动将多行同类数据合并为一行存在诸多困难和复杂的操作,容易出现错漏且难以保证数据合并的完全正确性,需要人工反复复核。作者因深受其苦,开发了一个具有特定功能的小工具。**重要亮点**-**手动合并数据的......
  • 面试必备之TCP知识
    概述关于TCP的杂乱知识点,不成体系,毕竟TCP真的太复杂。TCP,TransmissionControlProtocol;IP,InternetProtocol,两者共同组成TCP/IP协议族,包含一系列构成互联网基础的网络协议。OSI七层网络模型图片来自于OSI七层网络模型OSI七层由于太过严格,所以并没有应用在计算机中,其衍生的T......
  • rhTNFR-Fc中文文献-2005年(★5)
     rhTNFR-Fc中文文献-2005年 注册临床试验;类风湿关节炎;rhTNFR-Fc[1][1]胡大伟,鲍春德,陈顺乐,等.重组人Ⅱ型肿瘤坏死因子受体-抗体融合蛋白治疗类风湿关节炎双盲随机多中心对照临床研究[J/OL].中华风湿病学杂志,2005,9(11):664-668[2024-08-16].https://d.wanf......
  • Install clickhouse
    Installscript#!/bin/sh-eOS=$(uname-s)ARCH=$(uname-m)DIR=if["${OS}"="Linux"]thenif["${ARCH}"="x86_64"-o"${ARCH}"="amd64"]then#Requireatleastx86-64......
  • Spring Security系列之PasswordEncoder
    概述任何一个登录系统的密码不能明文存储,万一发生数据库泄漏事故(不管是内部人员导出数据库数据还是被黑客攻击破解数据库实例节点拿到数据库数据等,又或者是其他情况造成的),将产生巨大的损失。因此明文密码在存储到数据库之前需要加密处理。加密算法有很多,大致有如下分类:哈希函......
  • Spring Security系列之Handler
    概述与Spring、SpringMVC、SpringBoot一样,SpringSecurity里也有很多Handler接口、可以分为两大类,一类是普通的XxxHandler(见名知意),另一类是对应的ServerXxxHandler(RequestRejectedHandler除外)。以AuthenticationSuccessHandler为例,SpringSecurity中用于处理认证成功事件的接......
  • Spring Cloud系列之Ribbon
    概述负载均衡负载均衡,即LoadBalance,LB,通器常有两种实现手段,服务端和客户端。负载均衡器,是带有负载均衡功能的实体(或载体),本文不做严格区分;即缩写LB,可表示负载均衡策略,也可以表示负载均衡器。服务端LB的缺点,提供更强的流量控制权,但无法满足不同的消费者希望使用不同负载均衡策......
  • postgresql 定时收集表和索引统计信息 转发:https://blog.csdn.net/weixin_33711641/a
    --由于pg中表和索引的信息收集都是基于时间点的,对于以往的信息无法与现在的信息进行对比,故写下此工具进行统计信息收集--创建数据信息的schemacreateschemadb_stat;--创建收集信息的基础表createtabledb_stat.snapshot_pg_stat_all_indexes(relidint,indexrelidint,scheman......