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

C# 語言筆記:抽象類別限制與 out 參數型別安全

     編輯:關於C語言

議題一:抽象類別實作介面的強制性

現象

C# 中,即使類別宣告為 abstract,仍必須實作介面所有成員,不可留待衍生類別實作:

interface IOne {
    void A();
}

// 編譯錯誤:'BaseOne' does not implement interface member 'IOne.A()'
abstract class BaseOne : IOne {
    // 無法只宣告不實作 A()
}

對比 Java

Java 允許抽象類別部分實作介面,剩餘成員由具體子類別完成:

// Java - 合法
abstract class BaseOne implements IOne {
    // 可不實作 A()
}

設計哲學差異

  • C#:介面契約在編譯期強制完整滿足,抽象類別只是「不能實例化」而非「可部分實作介面」。這確保型別系統一致性,避免「實作了介面卻缺少方法」的執行期驚喜。
  • Java:抽象類別可作為介面的部分實作骨架,靈活度較高但增加型別系統複雜度。

C# 替代方案

  1. 明確介面實作:void IOne.A() { throw new NotImplementedException(); }(編譯通過,執行期失敗)
  2. 拆分介面:將介面細分為多個小介面,抽象類別只實作需要的部分
  3. 使用虛擬方法模式:不實作介面,改定義虛擬方法供子類別覆寫

議題二:out 參數的型別安全與指標的指標

核心規則

out 參數不支援協變:out Derived 不能轉為 out Base。

原因:out 參數本質是「指標的指標」

void Foo(out Base b) {
    b = new Base();  // 合法:將 Base 實例指派給 Base 參考
}

Derived d = null;
Foo(out d);  // 若允許:Foo 內部將 Base 指派給 d,導致 d 指向 Base 實例 → 型別安全破壞
d.DerivedOnlyMethod();  // 執行期崩潰!

記憶體模型視角

  • out T 相當於 T*(指向 T 的指標)
  • 方法內部對參數賦值 = 修改呼叫端變數的記憶體位址內容
  • 父類別指標與子類別指標無繼承關係,故不可互相轉換
  • 對比:in/ref/傳值參數支援協變(唯讀情境安全)

C# 7.2+ 解決方案:readonly ref / in 參數

// 唯讀參考,支援協變,避免複製大型結構體
void Process(in BigStruct data) { ... }

// 回傳唯讀參考
ref readonly BigStruct GetData() { ... }

總結

C# 在型別系統一致性上採取更嚴格立場:抽象類別必須完整實作介面、out 參數禁用協變。這些限制看似減少靈活性,實則在編譯期攔截整類執行期錯誤,符合 C#「靜態型別安全優先」的設計核心。

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