类型 · 值与引用

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 与显式类型。