首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 類別初始化順序深度解析:欄位初始化與建構子執行的真相

     編輯:關於C#

經典面試題:輸出什麼?


class Foo { public Foo(string s) => Console.WriteLine($"Foo ctor: {s}"); }
class Base { readonly Foo f = new Foo("Base init"); public Base() => Console.WriteLine("Base ctor"); }
class Derived : Base { readonly Foo f = new Foo("Derived init"); public Derived() => Console.WriteLine("Derived ctor"); }

new Derived();

實際輸出

Foo ctor: Derived init
Foo ctor: Base init
Base ctor
Derived ctor

執行順序鐵律

  1. 衍生類別欄位初始化 (由衍生至基底)
  2. 基底類別建構子 (由基底至衍生,遞迴含 `Object.ctor`)
  3. 衍生類別建構子本體

為什麼這樣設計?

**保證建構子執行時,所有欄位皆已初始化完成**。


// 反例:若順序為 Base ctor → Derived 欄位初始化
class Base {
    public Base() {
        if (this is Derived d) d.DoSomething(); // 此時 Derived 欄位尚未初始化!
        VirtualMethod(); // 多型呼叫衍生類別實作,存取未初始化欄位 → NullReference
    }
    protected virtual void VirtualMethod() {}
}
class Derived : Base {
    readonly Foo _foo = new Foo("init");
    public void DoSomething() => _foo.Bar(); // 爆炸
}

現行順序下,`Derived._foo` 在 `Base.ctor` 執行**前**就已就緒,虛擬方法呼叫安全。

關鍵陷阱:建構子中呼叫虛擬方法


class Base {
    public Base() => Initialize(); // 危險!
    protected virtual void Initialize() => Console.WriteLine("Base init");
}
class Derived : Base {
    private readonly List _data = new List { 1,2,3 };
    protected override void Initialize() => Console.WriteLine($"Derived init, Count={_data.Count}");
}
new Derived(); 
// 輸出: Derived init, Count=3  (欄位已初始化,安全)
// 但若 Derived 欄位初始化邏輯依賴 Base 狀態,則可能邏輯錯誤

鐵律:**建構子絕不呼叫虛擬方法** (或標記 `sealed override` / 私有方法)。

readonly 欄位在建構子賦值的特例


class Base {
    public readonly int X;
    public Base() { X = 10; Console.WriteLine($"Base ctor: X={X}"); }
}
class Derived : Base {
    public readonly int Y = 20; // 欄位初始化
    public Derived() { Y = 30; Console.WriteLine($"Derived ctor: Y={Y}"); }
}
new Derived();
// 輸出:
// Base ctor: X=10
// Derived ctor: Y=30
// 欄位初始化 Y=20 發生在 Base ctor 之後、Derived ctor 本體之前
// 建構子賦值 Y=30 覆寫欄位初始化值

總結速查表

階段動作順序
1衍生類別 `readonly`/欄位初始化器由衍生至基底
2基底類別建構子 (含 `base()`)由基底至衍生
3衍生類別建構子本體 (含 `this()` 遞迴)由基底至衍生

深刻理解此順序,能避免「建構子中存取未初始化欄位」、「虛擬方法呼叫陷阱」、「readonly 語意誤解」等經典 Bug,寫出更健壯的類別繼承體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved