C# 15 有什麼新內容

C# 15 包含以下新功能。 請使用最新的 Visual Studio 2026 內部版本或 .NET 11 預覽版 SDK 試用這些功能:

C# 15 是最新的 C# 預覽版本。 .NET 11 預覽版支援 C# 15。 如需詳細資訊,請參閱 C# 語言版本設定。

你可以從 .NET 下載頁面下載最新的 .NET 11 預覽版 SDK。 你也可以下載 Visual Studio 2026 Insider 版,其中包含 .NET 11 預覽版 SDK。

當新功能在公開預覽版本中可用時,「C# 的新內容」頁面會新增這些功能。 工作集區段在Roslyn 功能狀態頁面上,追蹤即將推出的功能何時合併到主要分支。

你可以在我們的 「破壞性變更」文章中找到 C# 15 中引入的任何破壞性變更。

備註

我們對這些功能的意見反應有興趣。 如果您發現上述任何新功能的問題,請在 dotnet/roslyn 存放庫中建立新的問題

集合表達式參數

你可以將參數傳給底層集合的建構子或工廠方法,方法是將 with(...) 元素作為集合表達式的第一個元素。 此功能允許您直接在集合表達式語法中指定容量、比較器或其他建構參數。

以下範例說明如何將容量參數傳遞給List<T>建構子,並將比較器傳遞給HashSet<T>

string[] values = ["one", "two", "three"];

// Pass capacity argument to List<T> constructor
List<string> names = [with(capacity: values.Length * 2), .. values];

// Pass comparer argument to HashSet<T> constructor
HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"];
// set contains only one element because all strings are equal with OrdinalIgnoreCase

欲了解更多關於集合表達式參數的資訊,請參閱 集合表達式的語言參考文章功能規範。 關於在集合初始化器中使用集合表達式參數的資訊,請參見 物件與集合初始化器

聯合型別

C# 15 引入了 聯合型別,代表一種可以是多種 case 型別之一的值。 請用關鍵字 union 宣告聯合:

public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);

public union Pet(Cat, Dog, Bird);

聯合元提供每種案例類型的隱式轉換,編譯器確保 switch 所有案例類型的表達式皆具完整:

Pet pet = new Dog("Rex");

string name = pet switch
{
    Dog d => d.Name,
    Cat c => c.Name,
    Bird b => b.Name,
};

執行時包含從 .NET 11 預覽 5 開始的 UnionAttributeIUnion 類型。 提案 規範 中的部分功能尚未實作。 這些功能會在未來的預覽中陸續推出。

欲了解更多資訊,請參閱語言參考中的 聯合型別功能規範

封閉階層

從 C# 15 開始,你可以對類別套用 closed 修飾符來宣告 封閉階層結構。 封閉類別只能在宣告它的組件內衍生,這會在編譯時固定直接子類別的集合:

public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;

由於編譯器知道每個直系後代,處理 switch 每個後代的表達式是窮盡的,不需要預設臂:

string Describe(GateState state) => state switch
{
    Closed => "closed",
    Open(var percent) => $"{percent}% open",
    // No warning: every direct descendant of 'GateState' is handled.
};

closed 修飾詞是上下文關鍵字。 一個 closed 類別是隱含 abstract 且不能與 sealedstaticabstract 明確修飾符結合的。 衍生不具傳遞性:封閉類別的未封閉衍生類別,仍可在其他組件中從其衍生。 若要將窮盡性檢查沿著階層向下延伸,也請將中間層後代標記為 closed

欲了解更多資訊,請參閱語言參考中的 封閉修飾符封閉階層結構模式 ,或功能 規範

擴展索引器

從 C# 15 開始,你可以在 區塊中宣告 extension。 擴充索引器讓你可以像索引器在接收器類型上宣告一樣,直接索引到接收器。 由於索引器始終是實例成員,宣告索引器的擴充區塊必須提供命名的接收參數。

以下範例會在 IEnumerable<int> 上宣告一個唯讀索引子,該索引子會傳回指定位置的元素:

public static class SequenceIndexer
{
    extension(IEnumerable<int> sequence)
    {
        public int this[int index] => sequence.ElementAt(index);
    }
}

你會對接收者進行索引存取,就好像索引子是接收者型別的成員一樣:

IEnumerable<int> numbers = Enumerable.Range(1, 10);
int third = numbers[2];

欲了解更多資訊,請參閱語言參考中的 擴充宣告功能規範

標示為 breakcontinue

從 C# 15 開始,breakcontinue 陳述式可以指定外層結構上的標籤名稱。 使用具標籤的 break 來結束外層迴圈或 switch 陳述式。 使用標籤 continue 來開始下一個封閉迴圈的迭代。

具名的 breakcontinue 可取代你原本必須用來控制巢狀迴圈流程的變通作法,例如在內層迴圈中設定布林旗標,然後在每一層外圈檢查,或使用會直接跳過這些迴圈的 goto。 直接在跳轉語句中命名目標迴路,省去了帳目管理,並使預期的控制流程更易閱讀。

outer: for (int row = 0; row < grid.Height; row++)
{
    for (int column = 0; column < grid.Width; column++)
    {
        if (grid[row, column].IsBlocked)
        {
            continue outer;
        }

        if (grid[row, column].IsGoal)
        {
            break outer;
        }
    }
}

將標籤直接放在它所識別的迴圈或 switch 語句上。 如果沒有標籤,breakcontinue 會保留其原本的行為,並以最內層適用的陳述式為目標。

IDE0410 風格規則會標示出可由具標籤的跳躍陳述式取代的布林旗標模式和 goto 模式,並展示各自的前後對照範例。

欲了解更多資訊,請參閱語言參考或功能規範中的跳躍語句

記憶體安全

C# 15 啟動了多版本計畫,重新定義語言中的記憶體安全。 目標是將 unsafe 上下文與實際存取未管理記憶體的操作綁定,而非指標型別的存在。 大多數記憶體安全漏洞都來自這些存取操作,因此語言使其對審查者和審核者特別有區別。

在完整模型中,成員上的 unsafe 會將其標記為 requires-unsafe:審核責任會轉移給呼叫者,呼叫者必須在 unsafe 上下文中使用該成員。 組裝會選擇執行此強制執行,編譯器則以 System.Runtime.CompilerServices.MemorySafetyRulesAttribute 屬性記錄該選擇。 模型還新增了一個 safe 情境關鍵字,將成員與明確佈局欄位標記 extern 為安全。 這些規則共同使得潛在記憶體不安全的邊界在整個程式中明確化。

第一步包含指標放鬆。 當你用語言 preview 版本編譯時,以下操作不再需要上下文 unsafe

  • 宣告指標型別並用運算 & 子取變數位址。
  • fixed 陳述,用來固定變數。
  • stackalloc 表達式轉換成指標。
  • 運算子 sizeof 適用於任何未管理型態。

以下範例會建立並釘選不含 unsafe 內容的指標:

int number = 42;
int* pointer = &number;

int[] numbers = [10, 20, 30];
fixed (int* first = numbers)
{
    // Dereferencing the pointer still requires an unsafe context.
}

存取指標所指向記憶體的操作,例如指標間接參照(*p)、指標成員存取(p->member)、指標元素存取(p[i])以及函式指標呼叫,仍然需要 unsafe 內容。

C# 15 也新增了一個 unsafe 表達式, unsafe(expression)該表達式為單一表達式建立不安全的上下文。 在語法上無法使用 unsafe 區塊的情況下,例如欄位初始化器、建構子初始化器或 catch 篩選器中,它就很有用:

class Header
{
    // A field initializer can't contain an unsafe block, but it can contain an unsafe expression.
    static readonly int Signature = unsafe(ReadSignature());

    static unsafe int ReadSignature()
    {
        int rawValue = 0x1234;
        int* pointer = &rawValue;
        return *pointer;
    }
}

與記憶體安全預覽的其他部分一樣, unsafe 表達式需要語言 preview 版本與 AllowUnsafeBlocks 編譯器選項。

編譯器也會將上下文關鍵字視為 safe 成員 extern 及明確佈局欄位的修飾符。 然而,requires-unsafe 成員模型,以及組件選擇加入更新後記憶體安全規則的功能,尚未可用,因此 safeunsafe 目前對呼叫端沒有作用。

欲了解更多資訊,請參閱語言參考或功能規範中的 Unsafe 程式碼、指標類型與函式指標

另請參閱