C#的對象系統是個單根系統,不支持類的多繼承,只支持多接口實現,這在 某種程度帶來了一些不便:我們在系統設計時經常會抽象出一些接口,並為接口 提供一個抽象類作為默認的實現,然後實際使用的類可以從抽象類派生。如果一 個類實現了多接口,那我們只能選擇一個抽象類作為祖先類,再將其他接口的實 現手工加到類中。這種情況在C#3.0中有了變化,我們現在可以利用C#3.0的擴展方法來實現一 個“受限的多繼承”。
C#3.0中引入了擴展方法,可以利用一個靜態類的靜態方法為一個類或者接口 添加方法,關鍵是添加的方法是包含實現的,由此我們可以在C#3.0中為接口提 供一個帶實現的方法聲明,而無需額外的實現類!如果一個類實現了多個這樣的 接口,就可以達到類似多繼承的效果。
讓我們用代碼測試一下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test35
{
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
{
}
class Program
{
static void Main(string[] args)
{
Test obj1 = new Test();
obj1.TestA();
obj1.TestB();
Console.ReadKey();
}
}
}
執行的結果:
ITestAHelper.TestA
ITestBHelper.TestB
ok!再多試一下,看看如果實現類中定義相同的方法會怎麼樣:
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();
//下面分別測試2種TestA()調用方式
obj1.TestA();
((ITestA)obj1).TestA();
Console.ReadKey();
}
}
執行的結果:
Test.TestA
ITestAHelper.TestA
從這次的結果看,這裡有一點點問題,如果實現類有相同的方法,接口的擴 展方法總是被接口的實現類隱藏,那麼如何多態?加上virtual試試看,似乎 static方法是不能使用virtual修飾符的:
public static virtual void TestA(this ITestA obj)
{
Console.WriteLine("ITestAHelper.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
看來這樣的話,擴展方法似乎總是被藏在接口的實現方法後面了,我沒想出 在接口變量中有什麼方法可以訪問到它。或許Reflection可以?我沒有嘗試下去 。
接口和類的方法聲明可以和擴展方法相同,那一個類能不能實現2個擁有相同 的擴展方法的接口呢?測試結果是編譯錯誤,代碼比較簡單,有興趣的朋友可以 自己試試看。
在此做個小小的總結,利用C#3.0的擴展方法,我們可以為接口提供默認的實 現而無需定義一個實現類,如果一個類實現了多個這樣的接口,就可以達到類似 “多重繼承”的效果。但是這種方法也有局限性,因為static方法不能使用 virtual修飾符,所以接口的擴展方法只能被接口的實現類隱藏,而不能重寫, 無法實現多態的效果,這是個比較大的缺點。這點如果能解決,就完美了。沒辦 法,這個世界沒有完美的東西啊。