.net C# 13中你应该知道的新增功能

C#(发音为“C sharp”)是由Microsoft开发的一种通用的面向对象的编程语言。它广泛用于构建各种类型的软件应用程序,从桌面应用程序到 Web 服务、游戏和移动应用程序。 C# 是 .NET 框架的一部分,它为开发人员提供了一组丰富的库和工具。

C# 最初于 2000 年推出,此后经历了多个版本的发展,每次迭代都引入了新功能和改进。它与 C 和 C++ 等语言有相似之处,但它也融合了 Java 等语言的概念。

C# 以其简单性、可读性和可伸缩性而闻名,使其成为小型项目和大型企业应用程序开发人员的热门选择。它支持现代编程范式,例如面向对象、命令式、函数式和面向组件的编程。此外,C# 通常与其他技术结合使用,例如用于 Web 开发的 ASP.NET 和用于跨平台移动开发的 Xamarin。

使用 C#13,我们不仅仅是在升级一种语言;我们正在拥抱一种思维方式——一种将过去的智慧与未来的兴奋融为一体的哲学。这就像踏上了一场惊心动魄的冒险,每个新功能都是一个等待发现的发现。

因此,当我们开始使用 C#13 及其新功能的旅程时,让我们记住,编码不仅仅是一种技能,而是一种艺术形式。让我们为我们的项目注入创造力和激情,让我们在不断发展的 C# 故事中写下我们自己的篇章。

资源

  • learn.microsoft.com

  • devblogs.microsoft.com

C# 13 新功能侧重于灵活性和性能。

让我们来谈谈这些新功能:

I. 参数集合

1。定义

参数修饰符不限于数组类型。

参数/参数集合是使用 params 修饰符声明的参数。

2。新增(使用 C# 13)

params 修饰符现在支持:

  • System.Span<T>,

  • System.ReadOnlySpan<T>

  • 和实现 System.Collections.Generic.IEnumerable<T 的类型>

使用 Add() 方法,以及来自 System.Collections.Generic 的相关接口,例如:

  • IEnumerable<T>,

  • IReadOnlyCollection<T>,

  • IReadOnlyList<T>,

  • ICollection<T> 和

  • IList<T>

Note :编译器管理接口参数的存储。

internal class Program {
  //--MAIN
  static void Main(string[] args) {
     Console.WriteLine(Sum(1, 2, 3, args.Length));
  }
//--NEW-SCHOOL PARAMS COLLECTIONS
 private static int SumNew(params ReadOnlySpan<int> values) {
        int sum = 0;
        foreach (var item in values) {
            sum += item;
        }
        return sum;
 }
//--OLD-SCHOOL PARAMS ARRAY
  private static int SumOld(params int[] values) {
    int sum = 0;
    foreach (var item in values) {
       sum += item;
    }
    return sum;
 }
}

3。标杆

使用 ReadOnlySpan 参数与数组参数比较方法

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

BenchmarkRunner.Run<BM>();

[MemoryDiagnoser(false)]
[HideColumns("RatioSD", "Alloc Ratio")]
public class BM {
 
  private decimal _value = 500m;
 
  [Benchmark]
  public decimal CallSumArray() => SumArray(1m, 100m, 200m, 300m, 400m, _value);
 
  [Benchmark(Baseline = true)]
  public decimal CallSumSpan() => SumSpan(1m, 100m, 200m, 300m, 400m, _value);
 
  private static decimal SumArray(params decimal[] values) {
      decimal sum = 0;
      foreach (var item in values) {
        sum += item;
      }
      return sum;
    }
 
   private static decimal SumSpan(params ReadOnlySpan<decimal> values) {
      decimal sum = 0;
      foreach (var item in values) {
         sum += item;
      }
      return sum;
    } 
}

图片

基准测试 SumArray 与 SumSpan

结果:

  • CallSumSpan 方法**速度提高了 28%,**并且不分配任何堆内存。

  • CallSumArray 方法分配了 120 个字节。

II. 新锁对象

.NET 9 运行时包括用于线程同步的新类型:System.Threading.Lock 类型。

System.Threading.Lock 类型通过其 API 提供更好的线程同步。

  • Lock.EnterScope( 输入_一个独占作用域_并返回一个名为 Lock.Scope 的对象。

  • Lock.Scope 是一个 ref 结构,支持 Dispose() 退出独占范围。

  • C# lock 语句现在对 Lock 对象使用_更新的 API_,而不是 System.Threading.Monitor

  • 如果将 Lock 对象转换为另一种类型,则会生成传统的 Monitor 代码。

→ 请参阅新锁对象的功能规范

二-1。例

using System;
using System.Threading.Tasks;

public class Account
{
   // Use `object` in versions earlier than C# 13
   private readonly System.Threading.Lock _balanceLock = new();
   private decimal _balance;

   public Account(decimal initialBalance)
    => _balance = initialBalance;

   public decimal Debit(decimal amount)
   {
       if (amount < 0)
       {
           throw new ArgumentOutOfRangeException(nameof(amount), 
           "The debit amount cannot be negative.");
       }

       decimal appliedAmount = 0;
       lock (_balanceLock)
       {
          if (_balance >= amount)
          {
               _balance -= amount;
               appliedAmount = amount;
          }
       }
       return appliedAmount;
   }

   public void Credit(decimal amount)
   {
       if (amount < 0)
       {
          throw new ArgumentOutOfRangeException(nameof(amount),      
          "The credit amount cannot be negative.");
       }

        lock (_balanceLock) { _balance += amount;}
    }

    public decimal GetBalance()
    {
        lock (_balanceLock){ return _balance;}
    }
}


class AccountTest
{
    static async Task Main()
    {
        var account = new Account(1000);
        var tasks = new Task[100];
        for (int i = 0; i < tasks.Length; i++)
        {
            tasks[i] = Task.Run(() => Update(account));
        }
        await Task.WhenAll(tasks);
        Console.WriteLine($"Account's balance is  
        {account.GetBalance()}");
        // Output:// Account's balance is 2000
    }

    static void Update(Account account)
    {
        decimal[] amounts = [0, 2, -3, 6, -2, -1, 8, -5, 11, -6];
        foreach (var amount in amounts)
        {
            if (amount >= 0)
            {
                account.Credit(amount);
            }
            else
            {
                account.Debit(Math.Abs(amount));
            }
        }
    }
}

解释:

此 C# 代码片段演示了帐户类的简单实现,该类管理银行帐户的余额,同时使用锁确保线程安全。让我们分解一下关键组件:

  1. 使用指令:代码首先使用指令导入必要的命名空间,包括 和 。SystemSystem.Threading.Tasks

  2. 帐户类:此类表示银行帐户,包括用于借记、贷记和检索帐户余额的方法。System.Threading.Lock 类型的对象用于在访问字段时确保线程安全。_balanceLock_balance

  3. 构造函数:该类具有一个构造函数,该构造函数使用初始余额初始化帐户。Account

  4. 借方法:如果有足够的资金可用,此方法从账户余额中扣除指定金额。如果请求的金额为负数或帐户余额不足,则会引发异常。

  5. 贷记方式:此方法将指定金额添加到帐户余额中。如果请求的金额为负数,则会引发异常。

  6. GetBalance 方法:此方法检索当前帐户余额。

  7. AccountTest 类:此类包含一个方法,该方法用作程序的入口点。它创建类的实例,生成多个任务以同时更新帐户,并等待所有任务完成。MainAccountTask.WhenAll

  8. 更新方法:此方法表示更新帐户余额的任务。它遍历一系列金额,根据每个金额的符号贷记或借记帐户。

III. 新的转义序列

字符字面表示单个字符,并由引号中的字符组成,如“a”。

以前,使用 \u001b 或 \x1b。

但是不建议使用 \x1b,因为如果 1b 后面的下一个字符是有效的十六进制数字,则这些字符将成为转义序列的一部分。

新增(使用 C# 13)

  • C# 13 允许使用 \e 作为 ESCAPE 字符 Unicode U+001B 的字符文本转义序列

Example :

string path = "\\eUsers\\eJohnDoe\\eDocuments\\eFile.txt";  
Console.WriteLine(path);  

Output :

C:\\Users\\JohnDoe\\Documents\\File.txt

四、方法组自然型

以前的行为是编译器为方法组构造完整的候选方法集。

如果需要自然类型,则从完整的候选方法集确定自然类型。 新的转义序列

新增(使用 C# 13)

  • 新行为是修剪每个作用域的候选方法集,删除那些不适用的候选方法。

  • 删除的方法是具有错误 arity 或未满足约束的泛型方法。

  • 仅当未找到候选方法时,该过程才会继续到下一个外部范围。

  • 此过程更紧密地遵循过载解决的一般算法。

  • 如果在给定范围内找到的所有候选方法都不匹配,则该方法组没有自然类型。

V. 隐式索引访问

V.1-BEFORE(C# 13 之前版本)

^ 运算符不能在对象初始值设定项表达式中使用,并且需要从前面为元素编制索引。

V.2-新增(使用 C# 13)

现在,您可以直接在对象初始值设定项中使用 ^ 运算符,这样可以更自然、更简洁地从末尾索引元素。

主要优点

  • 可读性:新语法更直观地以相反顺序或其他非标准序列初始化集合。

  • 简洁:减少初始化所需的代码量,使其更易于管理和理解。

  • 可维护性:更易于更新和修改初始化,而无需重新排序或索引出错。

V-3的。示例:BEFORE(在 C#13 之前)

public class TimerRemaining { 
  public int[] buffer = new int[10]; 
} 


var countdown = new TimerRemaining()
{
 buffer = new int[10] { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } 
};

for (int i = 0; i < countdown.buffer.Length; i++) 
{
    Console.WriteLine($"buffer[{i}] = {countdown.buffer[i]}"); 
}

Output:

buffer[0] = 9
buffer[1] = 8
buffer[2] = 7
buffer[3] = 6
buffer[4] = 5
buffer[5] = 4
buffer[6] = 3
buffer[7] = 2
buffer[8] = 1
buffer[9] = 0

解释:

在 C# 13 之前,每个元素都必须从一开始就按顺序显式分配,这使得代码在顺序颠倒时更长且更难阅读。

V-3-现在(使用 C#13)

public class TimerRemaining { 
 public int[] buffer = new int[10]; 
}

var countdown = new TimerRemaining() {
 buffer = 
 {
        [^1]  = 0,
        [^2]  = 1,
        [^3]  = 2,
        [^4]  = 3,
        [^5]  = 4,
        [^6]  = 5,
        [^7]  = 6,
        [^8]  = 7,
        [^9]  = 8,
        [^10] = 9
    }
};

for (int i = 0; i < countdown.buffer.Length; i++) 
{
    Console.WriteLine($"buffer[{i}] = {countdown.buffer[i]}"); 
}

Output:

buffer[0] = 9
buffer[1] = 8
buffer[2] = 7
buffer[3] = 6
buffer[4] = 5
buffer[5] = 4
buffer[6] = 3
buffer[7] = 2
buffer[8] = 1
buffer[9] = 0

VI. 扩展类型

扩展类型不在当前预览版中。

  • 扩展类型表示旨在为现有类型提供扩展成员的全新类型类别。

  • 这些类型包括方法、属性和其他成员,这些成员可以是特定于实例的,也可以是静态的。

  • 根据 Microsoft 的说法,扩展类型通过提供和构建定制基础对象特定实例的扩展来简化应用程序代码。

VI-示例:

public class Person()  
{  
    public required string GivenName { get; init; }   
    public required string SurName { get; init; }  
    public required Organization Organization { get; init; }   
}   
  
public class Organization()  
{  
    public required string Name { get; init; }  
    public required List<Team> Teams { get; init; }  
}   
  
public class Team()  
{  
    public required string TeamName { get; init; }  
    public required Person Lead { get; init; }  
    public required IEnumerable<Person> Members { get; init; }  
} 

扩展方法:

public implicit extension PersonExtension for Person  
{  
    public bool IsLead  
        => this.Organization  
            .Teams  
            .Any(team => team.Lead == this);  
}

解释-PersonExtension 类:

  • 定义为类命名的扩展方法。IsLeadPerson

  • 此扩展方法检查此人是否是其组织内任何团队的潜在顾客。

public explicit extension Lead for Person  
{  
    public IEnumerable<Team> Teams   
        => this.Organization  
            .Teams  
            .Where(team => team.Lead == this);  
}

解释-引线延伸方法:

  • 为类命名的显式扩展方法。LeadPerson

  • 此方法返回该人是领导者的团队。

public implicit extension OrganizationExtension for Organization  
{  
   private static Organization ourOrganization = new Organization("C# Design");  
  
   public static Person CreatePerson(string givenName, string surName)   
       => new(givenName, surName, ourOrganization);  
}

Explanation-OrganizationExtension 类:

  • 定义类的扩展方法以创建新人员。Organization

  • 此方法允许创建与扩展方法中指定的组织关联的新人员。

如果你喜欢我的文章,请给我一个赞!谢谢

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值