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

C# 基類與介面混合繼承宣告差異深度解析:介面重新對應機制

     編輯:關於C#

問題情境

給定基類 A 實作介面 IC,衍生類別 B 有兩種宣告方式:


interface IC { void M(); }
class A : IC { void IC.M() { Console.WriteLine("In A"); } }

// 方式一:隱含繼承介面
class B1 : A { }

// 方式二:顯式再次宣告介面
class B2 : A, IC { }

表面上行為相同,但多型行為卻大不同!

行為差異實測


class B1 : A { } // 無法重新實作 IC.M

class B2 : A, IC 
{ 
    public void IC.M() { Console.WriteLine("In B2"); } // 允許重新實作!
}

static void Main()
{
    var list = new List { new A(), new B1(), new B2() };
    foreach (var c in list) c.M();
}
/*
輸出:
In A
In A      <- B1 被迫繼承 A 的實作
In B2     <- B2 成功覆寫
*/

核心差異:介面重新對應

特性B1 : AB2 : A, IC
是否可重新實作介面成員❌ 編譯錯誤:'B1.IC.M()': containing type does implement interface 'IC'✅ 允許 public void IC.M() 顯式實作
多型行為鎖死基類實作可自行決定實作
IL 層面介面對應表指向 A 的實作介面對應表指向 B2 的新實作

解決方案:虛擬方法中介模式

若無法修改基類 A (如來自第三方組件),引入中介類別 AX:


class AX : A, IC
{
    // 使用 new 切斷與 A.M 的關聯,virtual 供後代覆寫
    public new virtual void M() 
    { 
        Console.WriteLine("In AX"); 
    }

    // 介面顯式實作轉呼叫虛擬方法
    void IC.M() => this.M();
}

class B1 : AX { public override void M() => Console.WriteLine("In B1"); }
class B2 : AX { public override void M() => Console.WriteLine("In B2"); }

IL 實作原理 (簡述)

  • CLR 透過 介面對應表 (Interface Map) 記錄每個類別實作介面成員的方法槽位。
  • B1 不宣告 IC,CLR 繼承 A 的對應表,IC.M 指向 A.IC.M。
  • B2 顯式宣告 IC,CLR 建立新對應表,允許 B2 提供新槽位方法 (顯式實作 void IC.M())。
  • 此機制稱為 介面重新對應,允許衍生類別「重新綁定」介面契約。

實務建議

  1. 設計基類時:介面成員盡量轉呼叫 protected virtual 方法,讓衍生類別自然覆寫,避免顯式實作鎖死。
  2. 繼承第三方基類:若需改變介面行為,宣告 class Derived : Base, IInterface 並提供顯式實作,或引入中介類別隔離。
  3. 避免不必要的重複宣告:若不需改變行為,class B : A 即可,減少認知負擔。

延伸:介面繼承鏈中的相同現象


interface IC1 { }
interface IC2 : IC1 { }

class A1 : IC1 { }
class A2 : IC1, IC2 { } // A1、A2 行為相同 (介面繼承自動包含)

class B1 : A1 { }
class B2 : A1, IC1 { } // B1、B2 行為不同!同樣觸發重新對應機制
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved