型別 · 值與引用

C# 裡 struct 與 class

宣告用的關鍵字不如賦值語義重要:class 變數持有的是指向同一個共享物件的引用;struct 變數持有的是它自己的一份複製。其他一切都由此而來。

class:兩個名字,一個物件

class 變數賦值時複製的是引用,不是物件。兩個名字指向同一個盒子:

class Dog
{
    public string Name;
    public Dog(string name) { Name = name; }
}

Dog a = new Dog("Rex");
Dog b = a;            // b 是同一個物件的第二個名字
b.Name = "Max";       // 通過 b 改名……
Console.WriteLine(a.Name);   // ……a 也跟著改名了
class Dog
{
    public string Name;
    public Dog(string name) { Name = name; }
}

Dog a = new Dog("Rex");
Dog b = new Dog("Rex");   // 一個真正的新物件
b.Name = "Max";
Console.WriteLine(a.Name);      // 沒被動過
Console.WriteLine(a == b);      // == 比較引用:不同物件 → False
                                // (內容相同,身份不同)

struct:賦值即複製

struct 把語義反過來。給 struct 變數賦值會複製整個值——從那一刻起兩個變數互不相干:

struct Point
{
    public int X;
    public Point(int x) { X = x; }
}

Point a = new Point(1);
Point b = a;        // 完整複製——b 有自己的儲存
b.X = 99;

Console.WriteLine(a.X);   // 1   —— a 從未被碰過
Console.WriteLine(b.X);   // 99

誠實說明:瀏覽器引擎目前把 struct 當 class 處理(引用語義)——這段程式在 Visual Studio 裡會像註釋所示列印 1 和 99。概念不變;在引擎長出值語義之前,複製行為請在真實編譯器裡驗證。

這個差異解釋的 gotcha

有沒有過這種經歷:通過一個變數改了欄位,另一個變數竟然也"看到"了變化?那是引用別名。它的映象:在方法裡改了 struct 的欄位,呼叫方的複製沒變?那是值複製。兩者都是各自語義下的正確行為——bug 是你期待了另一種:

場景classstruct
b = a; 複製的是……引用整個值
通過 b 修改會影響 a 嗎?會——同一個物件不會——各自的複製
a == b 意味著……同一身份欄位值相同(如果定義了 ==)
住在哪裡……堆上,垃圾回收內聯(棧上或在宿主內部)

到底選哪個?

大多數程式碼庫遵循的實用規則:

一分鐘自測

去練習場跑這段,按執行之前先預測輸出——就是上面的別名演示換了變數名:

Dog x = new Dog("One");
Dog y = x;
y = new Dog("Two");
Console.WriteLine(x.Name);   // 預測:One 還是 Two?(引用 vs 物件)

如果你答"One"——把 new Dog("Two") 賦給 y 只是讓 y 的引用改指向,它從不碰 x 指著的那個物件。相關閱讀:var 與顯式型別。