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

C# 3.0 中的「多重繼承」模擬:擴展方法的進階探討 (2)

     編輯:關於C語言

當實作類別定義了同名方法時會發生什麼?

我們繼續探討 C# 3.0 如何透過擴展方法為介面提供預設實作,以模擬多重繼承的效果。這次我們測試當實作類別本身定義了與擴展方法同名的方法時,呼叫行為會有何變化。

public interface ITestA { }
public static class ITestAHelper
{
    public static void TestA(this ITestA obj)
    {
        Console.WriteLine("ITestAHelper.TestA");
    }
}
public interface ITestB { }
public static class ITestBHelper
{
    public static void TestB(this ITestB obj)
    {
        Console.WriteLine("ITestBHelper.TestB");
    }
}
public class Test : ITestA, ITestB
{
    // 此方法與 ITestA 的 TestA() 擴展方法同名
    public void TestA()
    {
        Console.WriteLine("Test.TestA");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Test obj1 = new Test();
        // 分別測試兩種 TestA() 呼叫方式
        obj1.TestA();
        ((ITestA)obj1).TestA();
        Console.ReadKey();
    }
}

執行結果:

Test.TestA
ITestAHelper.TestA

觀察與分析

從結果可以發現一個關鍵行為:當實作類別擁有同名實例方法時,該方法會隱藏介面的擴展方法。直接對實例呼叫 obj1.TestA() 會執行類別自身的方法;但若將實例轉型為介面 ((ITestA)obj1).TestA(),則會呼叫擴展方法。

這引出了一個問題:如何實現多態? 如果擴展方法總是被實作類別隱藏,我們就無法透過介面參考來動態調度不同的實作。

嘗試加上 virtual 修飾符

直覺上我們可能想將擴展方法標記為 virtual 以允許覆寫,但編譯器會報錯:

public static virtual void TestA(this ITestA obj) // 編譯錯誤:static 方法不能使用 virtual
{
    Console.WriteLine("ITestAHelper.TestA");
}

靜態方法不支援 virtual、override 或 abstract,這條路走不通。

若介面本身也定義了同名方法呢?

我們修改介面 ITestA,加入 void TestA(); 宣告:

public interface ITestA
{
    void TestA();
}
public static class ITestAHelper
{
    public static void TestA(this ITestA obj)
    {
        Console.WriteLine("ITestAHelper.TestA");
    }
}

執行結果:

Test.TestA
Test.TestA

這時候,擴展方法完全被實作類別的方法「藏」起來了,即使透過介面參考呼叫,也會執行實作類別的方法。擴展方法似乎永遠無法被介面變數存取。或許用反射可以繞過?但這已經超出了正常語法的範疇,我們暫不深究。

一個類別能實作兩個擁有相同擴展方法的介面嗎?

測試結果是編譯錯誤。編譯器無法決定該呼叫哪個擴展方法,導致歧義。感興趣的讀者可以自行嘗試驗證。

小結

  • 利用 C# 3.0 的擴展方法,我們可以為介面提供預設實作,無需定義具體實作類別。
  • 若一個類別實作多個這類介面,即可達到類似「多重繼承」的程式碼重用效果。
  • 缺陷:靜態方法無法使用 virtual,導致擴展方法只能被實作類別隱藏,無法被覆寫,也就無法實現真正的多態。這是一個較大的限制。

若未來語言層面能解決此限制(例如允許介面預設實作),將會更完美。但正如俗話所說:「這個世界沒有完美的東西。」

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