前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >解锁 C# 11:您必须了解的 15 个新功能(带有真实示例)

解锁 C# 11:您必须了解的 15 个新功能(带有真实示例)

作者头像
郑子铭
发布2025-01-07 10:54:57
发布2025-01-07 10:54:57
16000
代码可运行
举报
运行总次数:0
代码可运行

引言

C# 11带来了一系列新特性,旨在使开发流程更加顺畅、高效。从改进的字符串处理到更灵活的泛型,该版本所引入的增强功能既能满足日常编码需求,也能适配高级编程需求。在本文中,我们将深入探究这些新特性,为每个特性探讨示例,并了解它们的使用场景。

1. 原始字符串字面量

原始字符串字面量使得处理多行字符串更为简便,无需对特殊字符进行转义,也不用担心缩进问题。

示例1:SQL查询

代码语言:javascript
代码运行次数:0
复制
string sqlQuery = """
    SELECT * FROM Users
    WHERE Age > 
    ORDER BY LastName;
    """;

在之前的版本中,你必须为引号使用转义字符,并确保换行符符合你的意图。

示例2:JSON数据

代码语言:javascript
代码运行次数:0
复制
string jsonData = """
    {
        "name": "John Doe",
        "age": ,
        "city": "New York"
    }
    """;

与使用常规字符串相比,这简化了JSON数据的表示形式。

优缺点:

  • 优点:更易于维护格式化的字符串,例如JSON、XML和SQL查询。
  • 缺点:对于非常大的文本块,管理起来可能会变得困难。
  • 实际应用场景:存储HTML电子邮件的模板或配置数据,在这些场景中,保持精确的格式至关重要。

2. 泛型数学支持

泛型数学支持使泛型类型能够进行算术运算。这对于需要对不同数值类型进行操作的数学库或算法特别有用。

示例1:计算平均值

代码语言:javascript
代码运行次数:0
复制
public static T Average<T>(T x, T y) where T : INumber<T>
{
    return (x + y) / T.Create();
}

此方法可以计算任何数值类型(如intdoubledecimal等)的平均值。

示例2:泛型二维向量类

代码语言:javascript
代码运行次数:0
复制
public classVector2D<T>whereT:INumber<T>
{
    publicT X {get;}
    publicT Y {get;}
    publicVector2D(T x,T y)
    {
        X = x;
        Y = y;
    }
    publicTMagnitude()=> T.Sqrt(X * X + Y * Y);
}

这使得Vector2D能够与任何数值类型一起工作。

优缺点:

  • 优点:减少代码重复并提高性能。
  • 缺点:如果你不熟悉泛型约束,实现起来可能会有挑战性。
  • 实际应用场景:构建一个财务计算库,其中的方法需要针对不同用例支持decimaldouble类型。

3. 泛型特性

C# 11允许使用泛型参数定义特性,这使得特性更具可复用性且类型安全。

示例1:验证特性

代码语言:javascript
代码运行次数:0
复制
public classValidateTypeAttribute<T>:Attribute
{
    publicstring ErrorMessage {get;}
    publicValidateTypeAttribute(string errorMessage)
    {
        ErrorMessage = errorMessage;
    }
}

示例2:自定义序列化特性

代码语言:javascript
代码运行次数:0
复制
[CustomSerializer<MyType>()]
public class MyClass { /*...*/ }

优缺点:

  • 优点:减少了为不同类型创建多个特性的需求。
  • 缺点:增加了设计特性逻辑的复杂性。
  • 实际应用场景:一个日志记录特性,它根据方法的返回类型以不同方式记录方法。

4. UTF-8字符串字面量

UTF-8字符串字面量有助于在处理UTF-8编码文本时优化内存使用。

示例1:定义UTF-8字符串

代码语言:javascript
代码运行次数:0
复制
ReadOnlySpan<byte> utf8Message = "Hello, world!"u8;

这使你能够直接处理UTF-8编码的字符串。

示例2:提升Web应用程序性能

代码语言:javascript
代码运行次数:0
复制
var utf8Data = Encoding.UTF8.GetBytes("Some text data");

将文本数据直接以UTF-8格式存储可以减少网络通信中的内存开销。

优缺点:

  • 优点:减少内存消耗,特别是对于处理大量文本数据的应用程序而言。
  • 缺点:除非专门处理UTF-8编码的数据,否则受益有限。
  • 实际应用场景:处理JSON有效载荷且需要UTF-8编码的Web API。

5. 字符串插值表达式中的换行

此功能允许你在字符串插值块中使用换行符,使复杂的插值更具可读性。

示例1:使用多个变量记录日志

代码语言:javascript
代码运行次数:0
复制
Console.WriteLine($"""
    The user {user.Name} has logged in.
    Role: {user.Role}
    Last login: {user.LastLogin}
    """);

示例2:电子邮件模板

代码语言:javascript
代码运行次数:0
复制
string emailContent = $"""
    Hi {user.FirstName},

    Welcome to our service. Your account is now active.

    Regards,
    Team
    """;

优缺点:

  • 优点:提高复杂字符串插值的可读性。
  • 缺点:可能会被过度使用,导致代码杂乱。
  • 实际应用场景:创建动态电子邮件模板或详细的日志消息。

6. 列表模式

列表模式允许对列表或数组进行模式匹配,从而更易于检查集合中的特定结构。

示例1:匹配特定模式

代码语言:javascript
代码运行次数:0
复制
int[] numbers = { , ,  };
if (numbers is [, , ])
{
    Console.WriteLine("The array contains 1, 2, and 3.");
}

示例2:检测前缀

代码语言:javascript
代码运行次数:0
复制
if (numbers is [,..])
{
    Console.WriteLine("The array starts with 1.");
}

优缺点:

  • 优点:简化了列表结构检查。
  • 缺点:对于刚接触模式匹配的开发人员来说,可能不太直观。
  • 实际应用场景:在配置验证工具中检查列表是否以某些元素开头或结尾。

7. 文件局部类型

文件局部类型允许你将类型的作用域限制在其定义所在的文件内。

示例1:辅助类

代码语言:javascript
代码运行次数:0
复制
file class LoggerHelper
{
    public static void Log(string message) => Console.WriteLine(message);
}

示例2:内部结构体

代码语言:javascript
代码运行次数:0
复制
file struct Vector3D { /*...*/ }

优缺点:

  • 优点:改进了封装性,防止意外访问。
  • 缺点:可能会使在大型代码库中导航变得更加困难。
  • 实际应用场景:库中不应暴露给其他文件的内部辅助类。

8. 必需成员

C# 11引入了必需成员的概念,允许你指定在创建对象时某些属性或字段必须进行初始化。这对于不可变对象(其中某些属性必须在初始化期间设置)特别有用。

示例1:数据传输对象(DTO)

代码语言:javascript
代码运行次数:0
复制
public classUser
{
    public required string Name {get;init;}
    public required int Age {get;init;}
}

// 使用方式:
var user =newUser{ Name ="John Doe", Age =};// 有效
var user2 =newUser{ Name ="John Doe"};// 错误:'Age'是必需的

示例2:不可变设置对象

代码语言:javascript
代码运行次数:0
复制
public class AppSettings
{
    public required string DatabaseConnection { get; init; }
    public required string ApiKey { get; init; }
}

这有助于确保始终提供必要的设置,防止运行时出现问题。

优缺点:

  • 优点:增强了数据完整性,防止关键字段缺失。
  • 缺点:为对象初始化增加了更多的样板代码。
  • 实际应用场景:确保在创建配置对象时,始终具有诸如连接字符串、API密钥或用户数据等必需参数。

9. 自动默认结构体

借助自动默认结构体特性,C# 11会自动将结构体初始化为其默认值,在处理不需要特定初始化的结构体时,可使代码更简洁。

示例1:点结构体初始化

代码语言:javascript
代码运行次数:0
复制
public structPoint
{
    publicint X {get;set;}
    publicint Y {get;set;}
}

// 在C# 11中,无需手动设置默认值:
Point p =new();// X和Y被初始化为0。

在之前的版本中,你必须确保手动初始化结构体,以避免出现未初始化状态的错误。

示例2:默认构造函数行为

代码语言:javascript
代码运行次数:0
复制
public struct Circle
{
    public double Radius { get; set; }
}

Circle circle = new(); // 半径自动设置为0。

优缺点:

  • 优点:减少与未初始化字段相关的错误,减少样板代码。
  • 缺点:如果不希望自动设置默认值,可能会引入意外行为。
  • 实际应用场景:在图形应用程序中,将结构体用于像点、颜色或尺寸这样的简单数据结构。

10. 对常量字符串进行Span模式匹配

此功能允许将Span<char>直接与常量字符串进行模式匹配,这可以显著提高字符串处理和解析性能,特别是在处理高性能应用程序(如解析器或编译器)时。

示例1:解析命令

代码语言:javascript
代码运行次数:0
复制
ReadOnlySpan<char> command ="START_PROCESS";

if(command is"START_PROCESS")
{
    Console.WriteLine("Process started.");
}
elseif(command is"STOP_PROCESS")
{
    Console.WriteLine("Process stopped.");
}

在之前的版本中,你需要进行字符串比较,或者将Span<char>转换回字符串。

示例2:处理文本协议

代码语言:javascript
代码运行次数:0
复制
ReadOnlySpan<char> protocol ="HTTP/1.1";

if(protocol is"HTTP/1.1")
{
    Console.WriteLine("Handling HTTP/1.1 request");
}
elseif(protocol is"HTTP/2")
{
    Console.WriteLine("Handling HTTP/2 request");
}

优缺点:

  • 优点:减少内存分配,加快字符串比较速度。
  • 缺点:需要熟悉Span<char>以及注重性能的编程方式。
  • 实际应用场景:在实现解析器或命令行界面时,性能至关重要,且需要在不进行内存分配的情况下解析字符串。

11. 扩展的nameof作用域

在C# 11中,nameof运算符的作用域得到了扩展,允许它在更多场景中使用,例如在特性或lambda表达式中。此功能通过改进重构能力,使代码更易于维护。

示例1:在特性中使用nameof

代码语言:javascript
代码运行次数:0
复制
[DisplayName(nameof(User.FirstName))]
public string FirstName { get; set; }

在之前的版本中,nameof的使用更为受限,常常需要采取变通方法。

示例2:在lambda表达式中使用nameof

代码语言:javascript
代码运行次数:0
复制
Func<int, string> getName = (id) => $"{nameof(id)}: {id}";

优缺点:

  • 优点:提供更好的重构支持,提高代码可读性。
  • 缺点:在不增加显著价值的上下文中可能会被误用。
  • 实际应用场景:使用nameof来确保验证逻辑中的属性名称与实际属性名称保持同步,以降低重构期间出现错误的风险。

12. 数值型IntPtr

C# 11中的数值型IntPtr允许更好地处理整数指针操作,特别是在涉及低级编程或与非托管代码进行互操作的场景中。

示例1:指针算术运算

代码语言:javascript
代码运行次数:0
复制
IntPtr pointer = new IntPtr();
IntPtr result = pointer + ; // 现在可以直接进行算术运算。

在之前的版本中,IntPtr在进行算术运算时需要在int类型之间进行转换。

示例2:内存管理

代码语言:javascript
代码运行次数:0
复制
IntPtr baseAddress =...;
IntPtr offsetAddress = baseAddress + ;

这在访问内存映射文件或进行本机互操作等场景中很有用。

优缺点:

  • 优点:对于低级操作,代码更简洁,减少了类型转换。
  • 缺点:使用场景局限于涉及指针的情况。
  • 实际应用场景:游戏开发或与硬件交互的应用程序,在这些场景中,高效的内存操作至关重要。

13. ref字段和作用域ref

C# 11引入了在结构体中声明ref字段的能力,通过引用现有数据而不复制数据,实现更高效的内存管理。

示例1:结构体中的ref字段

代码语言:javascript
代码运行次数:0
复制
public structBufferWrapper
{
    privaterefint _value;

    publicBufferWrapper(refintvalue)
    {
        _value =refvalue;
    }
}

在之前的版本中,这需要诸如使用指针或不安全代码之类的变通方法。

示例2:作用域ref参数

代码语言:javascript
代码运行次数:0
复制
public void ModifyValue(scoped ref int value)
{
    value *= ;
}

优缺点:

  • 优点:通过避免不必要的复制来提高性能。
  • 缺点:增加了复杂性,特别是在理解ref语义方面。
  • 实际应用场景:高性能数据处理,例如在内存中操作大型数据集且无需复制的自定义数据结构。

14. 改进的方法组到委托的转换

C# 11允许更顺畅地将方法组转换为委托,减少了显式转换或使用中间变量的需求。

示例1:事件处理程序

代码语言:javascript
代码运行次数:0
复制
public classEventHandlerExample
{
    publiceventAction OnEvent;

    publicvoidInitialize()
    {
        OnEvent += HandleEvent;
    }

    privatevoidHandleEvent(){/*... */}
}

在之前的版本中,你可能需要手动将HandleEvent转换为Action

示例2:简化LINQ查询

代码语言:javascript
代码运行次数:0
复制
var numbers = new[] { , , , ,  };
var squares = numbers.Select(Math.Pow);

优缺点:

  • 优点:代码更简洁、更具可读性。
  • 缺点:如果过度使用,可能会掩盖方法细节。
  • 实际应用场景:注册事件处理程序或在LINQ操作中直接使用现有方法。

15. 警告波7

警告波7引入了一组新的编译器警告,旨在提高代码质量,并在开发周期的早期捕获潜在问题。

示例1:抑制警告

代码语言:javascript
代码运行次数:0
复制
#pragma warning disable CS9001 // 示例警告代码
// 存在潜在问题的代码...
#pragma warning restore CS9001

示例2:迁移旧代码 警告可以帮助识别旧代码中的过时模式,并建议现代的替代方案。

优缺点:

  • 优点:有助于维持高质量的代码,减少错误。
  • 缺点:可能需要对现有代码进行调整以解决新的警告。
  • 实际应用场景:更新大型代码库以确保与最新的C#特性兼容,同时处理新警告所标识的潜在问题。

C# 11中的新增特性为开发人员提供了强大的工具,无论是在高级还是低级编程中,都能使代码更简洁、性能更优、灵活性更强。无论你是在处理内存管理、设计现代API,还是仅仅希望编写更简洁、更易于维护的代码,C# 11都有所助益。通过这些示例和场景,你可以利用该语言的最新功能来构建更高效、更健壮的应用程序。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 1. 原始字符串字面量
  • 2. 泛型数学支持
  • 3. 泛型特性
  • 4. UTF-8字符串字面量
  • 5. 字符串插值表达式中的换行
  • 6. 列表模式
  • 7. 文件局部类型
  • 8. 必需成员
  • 9. 自动默认结构体
  • 10. 对常量字符串进行Span模式匹配
  • 11. 扩展的nameof作用域
  • 12. 数值型IntPtr
  • 13. ref字段和作用域ref
  • 14. 改进的方法组到委托的转换
  • 15. 警告波7
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档