C#12新功能有哪些?

2023-12-04 12:04:14

前言

作為.NET 8釋出會的一部分,微軟於11月14日釋出了C#12的新功能,這也是目前.NET的最新版本。正如之前公佈的那樣,最顯著的改進包括了集合表示式、主建構函式、任何型別的別名以及lambda表示式中引數提供預設值。

主建構函式

C#12擴充套件了主建構函式,現在可以在任何class和struct中建立主建構函式。 主建構函式不再侷限於record型別。這一改進允許在類宣告中直接定義建構函式引數。

主建構函式引數的用途有以下三點:

  • 作為 base() 建構函式呼叫的引數
  • 初始化成員欄位或屬性
  • 參照範例成員中的建構函式引數

主建構函式引數是在整個類定義範圍內的引數,值得注意的是,編譯器僅在 record 型別(record class 或 record struct 型別)中為主建構函式引數生成公共屬性,從而可以簡化成員管理,下面是主建構函式的程式碼範例:

public class BankAccount(string accountID, string owner)
{
    public string AccountID { get; } = accountID;
    public string Owner { get; } = owner;

    public override string ToString() => $"Account ID: {AccountID}, Owner: {Owner}";
}

集合表示式

集合表示式,簡化了建立各種集合的語法,提供了一種統一的方法,在初始化陣列、列表或跨度時,無需使用不同的語法,以下範例演示了集合表示式的使用:

// Create an array:
int[] a = [1, 2, 3, 4, 5, 6, 7, 8];

// Create a list:
List<string> b = ["one", "two", "three"];

// Create a span
Span<char> c  = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'i'];

// Create a jagged 2D array:
int[][] twoD = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

// Create a jagged 2D array from variables:
int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[][] twoDFromVariables = [row0, row1, row2];

此外,展開運運算元(集合表示式中的 ..)可將其引數替換為該集合中的元素,引數必須是集合型別,可以簡化多個集合操作的過程。

int[] row0 = [1, 2, 3];
int[] row1 = [4, 5, 6];
int[] row2 = [7, 8, 9];
int[] single = [..row0, ..row1, ..row2];
foreach (var element in single)
{
    Console.Write($"{element}, ");
}
// output:
// 1, 2, 3, 4, 5, 6, 7, 8, 9,

ref readonly 引數&內聯陣列

ref readonly 引數內聯陣列這兩個新功能,可以增強原始記憶體處理能力,提高應用程式效能。內聯陣列使開發人員能夠建立固定大小的 struct 型別陣列,使開發人員能夠優化程式碼以提高效率。內聯陣列速度很快,因為它們依賴於指定長度的精確佈局。內聯陣列是一種具有單個欄位的型別,並用指定陣列長度的InlineArrayAttribute 進行標記。

[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer
{
    private int _element0;
}

// Usage
var buffer = new Buffer();

for (int i = 0; i < 10; i++)
    buffer[i] = i;

foreach (var i in buffer)
    Console.WriteLine(i);

此外,C#12還引入了攔截器Experimental屬性兩個試驗性功能。用 Experimental 特性標記的程式集或模組中宣告的所有型別都是實驗性的。 如果存取其中任何一種型別,編譯器都會發出警告。 可以禁用這些警告以試用實驗性功能。攔截器允許將特定方法呼叫重新路由到不同的程式碼,它適用於一些高階場景,特別是允許更好的提前編譯(AOT)。

lambda 表示式的輸入引數

從C#12開始,Lambda 表示式中的引數可以提供預設值。這意味著可以為元素型別、陣列型別、指標型別或其他不安全型別建立語意別名。

var IncrementBy = (int source, int increment = 1) => source + increment;

Console.WriteLine(IncrementBy(5)); // 6
Console.WriteLine(IncrementBy(5, 2)); // 7

1.非同步 lambda

通過使用 async 和 await 關鍵字,你可以輕鬆建立包含非同步處理的 lambda 表示式和語句。 例如,下面的程式碼範例包含一個調非同步方法 ExampleMethodAsync。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            await ExampleMethodAsync();
            textBox1.Text += "\r\nControl returned to Click event handler.\n";
        };
    }

    private async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

2.表示式 lambda

表示式位於 => 運運算元右側的 lambda 表示式稱為「表示式 lambda」。 表示式 lambda 會返回表示式的結果,並採用以下基本形式:

(input-parameters) => expression

3.語句 lambda

語句 lambda 與表示式 lambda 類似,只是語句包括在大括號中:

(input-parameters) => { <sequence-of-statements> }

4.lambda 表示式和元組

C# 語言提供對元組的內建支援。 可以提供一個元組作為 Lambda 表示式的引數,同時 Lambda 表示式也可以返回元組。 在某些情況下,C# 編譯器使用型別推理來確定元組元件的型別。

可通過用括號括住用逗號分隔的元件列表來定義元組。 下面的範例使用包含三個元件的元組,將一系列數位傳遞給 lambda 表示式,此表示式將每個值翻倍,然後返回包含乘法運算結果的元組(內含三個元件)。

Func<(int, int, int), (int, int, int)> doubleThem = ns => (2 * ns.Item1, 2 * ns.Item2, 2 * ns.Item3);
var numbers = (2, 3, 4);
var doubledNumbers = doubleThem(numbers);
Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");
// Output:
// The set (2, 3, 4) doubled: (4, 6, 8)

總結

綜上所述,C#12的新功能為開發者帶來了更多的靈活性、可讀性和效率。無論是是新手還是有經驗的開發者,都能從這些功能中受益。無論是程式碼的編寫、偵錯還是效能優化,C#12為提供了更多的工具和選項。因此,開發者應緊跟技術的步伐,不斷學習和應用C#12的新功能,以保持在C#開發領域的競爭力。

有關C#12可用功能的更多資訊,可存取官方檔案

擴充套件連結:

Redis從入門到實踐

一節課帶你搞懂資料庫事務!

Chrome開發者工具使用教學

從表單驅動到模型驅動,解讀低程式碼開發平臺的發展趨勢

低程式碼開發平臺是什麼?

基於分支的版本管理,幫助低程式碼從專案交付走向客製化化產品開發