| 特性 | struct (值型別) | class (參考型別) |
|---|---|---|
| 記憶體配置 | Stack (區域變數) / Inline (陣列/欄位) | Heap (Managed Heap) |
| 指派行為 | 複製整個實例資料 | 複製參考 (指向同一物件) |
| 預設值 | 所有欄位歸零 (0/null/false) | null |
| 繼承 | 不可繼承其他 struct/class,隱性繼承 ValueType | 單一繼承,可繼承介面 |
| 介面實作 | 可實作介面 | 可實作介面 |
| 解構函式 | 不可宣告 | 可宣告 (Finalizer) |
| 建構函式 | 不可有無參數建構函式 (C# 10 前) | 可有無參數建構函式 |
| 欄位初始化 | 宣告時不可初始化 (除非 const/static) | 可直接初始化 |
| null 能力 | 需包裝為 Nullable<T> (T?) | 天然可為 null |
public struct Point
{
public int X;
public int Y;
// C# 10+ 允許無參數建構函式,但仍會被忽略 (new Point() 仍歸零)
public Point(int x, int y) { X = x; Y = y; }
public override string ToString() => $"({X}, {Y})";
}
// 使用
Point p1 = new Point(3, 4); // 呼叫建構函式
Point p2 = new Point(); // X=0, Y=0 (歸零)
Point p3; // 未初始化,使用前必須指派
p3.X = 10; p3.Y = 20; // 現在可用
// 複製語意:p4 獲得 p1 的獨立副本
Point p4 = p1;
p4.X = 100; // p1.X 仍為 3,互不影響
public struct Vector2 : IEquatable, IFormattable
{
public float X, Y;
public Vector2(float x, float y) { X = x; Y = y; }
// 運算子多載
public static Vector2 operator +(Vector2 a, Vector2 b)
=> new Vector2(a.X + b.X, a.Y + b.Y);
public static Vector2 operator *(Vector2 v, float s)
=> new Vector2(v.X * s, v.Y * s);
// 介面實作
public bool Equals(Vector2 other) => X == other.X && Y == other.Y;
public override bool Equals(object obj) => obj is Vector2 v && Equals(v);
public override int GetHashCode() => HashCode.Combine(X, Y);
public string ToString(string format, IFormatProvider provider)
=> $"({X.ToString(format, provider)}, {Y.ToString(format, provider)})";
}
void Method()
{
Point p = new Point(1, 2); // 直接在 Stack 配置 8 bytes (兩個 int)
// 無 GC 壓力,方法結束自動釋放
}
Point[] points = new Point[1000];
// 連續記憶體 1000 * 8 bytes = 8KB,單一陣列物件於 Heap
// 優點:Cache 友好、無額外物件標頭、GC 掃描快
class Container
{
Point _center; // 直接內嵌於 Container 物件中,非獨立 Heap 物件
}
Point p = new Point(1, 2);
object boxed = p; // Boxing: Heap 配置物件、複製值、加上標頭
Point unboxed = (Point)boxed; // Unboxing: 型別檢查、複製值回 Stack
// 避免裝箱技巧:
// 1. 使用泛型 List 而非 ArrayList
// 2. 介面約束 where T : struct 避免裝箱
// 3. 實作介面時小心:介面變數持有 struct 會裝箱
IEquatable eq = p; // 裝箱發生!
Point? nullable = null; // 實際為 Nullable
nullable = new Point(5, 6);
if (nullable.HasValue) Console.WriteLine(nullable.Value);
Console.WriteLine(nullable.GetValueOrDefault()); // 安全取值
// C# 7+ 模式比對
if (nullable is Point pt) Console.WriteLine(pt);
✅ 適用:
readonly struct C# 7.2+)❌ 不適用:
// 唯讀結構:編譯器強制所有欄位 readonly,方法隱性 this 為 in 參數
public readonly struct ImmutablePoint
{
public int X { get; }
public int Y { get; }
public ImmutablePoint(int x, int y) { X = x; Y = y; }
}
// ref struct:只能存在於 Stack,不可作為類別欄位、陣列元素、Boxing
public ref struct SpanWrapper
{
public Span Data;
// 只能用於同步方法參數、區域變數
}