Deriving from Multiple Base Interfaces 從多個基接口派生
與類不同,接口可以有不止一個基接口。清單12-8含有一個例子。
interface IProductCalculator { int CalculateProduct(int x, int y); } interface ISumCalculator { int CalculateSum(int x, int y); } interface ISubtractionCalculator { int CalculateSubtraction(int x, int y); } interface ICombinedCalculator : IProductCalculator, ISumCalculator, ISubtractionCalculator { int CalculateDivision(int x, int y); }
清單12-8中的最先三個接口,IProductCalculator、ISumCalculator、以及ISubtractionCalculator是互不相關的,每一個都指定了一個單一的方法。最後一個接口從這三個派生而來,意即,派生接口指明了這三個接口指定的成員,再加上它自己所指定的成員。
為了能從多個基接口派生,簡單地用逗號分隔每個基接口的名字即可,如清單12-8中的黑體所示。一個實現ICombinedCalculator接口的類必須實現所有四個方法,像這樣:
class Calculator : ICombinedCalculator { public int CalculateDivision(int x, int y) { return x / y; } public int CalculateProduct(int x, int y) { return x * y; } public int CalculateSum(int x, int y) { return x + y; } public int CalculateSubtraction(int x, int y) { return x - y; } }
當一個類實現有多個基接口的接口時,從這個類生成的對象可以上溯到任何一個基接口。上溯完成時,只有基接口中指定的成員可以被訪問,像這樣:
// create an object and upcast it to the combined interface ICombinedCalculator calc = new Calculator(); // upcast to the base interfaces and call the method that each defines IProductCalculator prodCalc = calc; int prodResult = prodCalc.CalculateProduct(10, 10); ISumCalculator sumCalc = calc; int calcResult = sumCalc.CalculateSum(10, 10); ISubtractionCalculator subCalc = calc; int subResult = subCalc.CalculateSubtraction(10, 2);
你也可以明確地把一個基接口轉換成另一個(但必須確保你正在轉換的這個對象這兩個接口都實現了),像這樣:
// explicitly cast from one base interface to another prodCalc = (IProductCalculator)subCalc;
Defining a Partial Interface 定義一個部分接口
接口可以用partial關鍵詞進行修飾,並在幾個地方進行定義。就好像部分類那樣(第6章討論過),編譯器將把這幾個部分元素組合成一個單一的接口定義。成員說明必須在所有部分接口之間是唯一的。清單12-9演示了一個部分接口。
partial interface ICalculator { int CalculateProduct(int x, int y); } partial interface ICalculator { int CalculateSum(int x, int y); }
這兩個部分接口被定義在同一個代碼文件中,目的是生成一個方便的示例,但通常它們是在不同的代碼文件中。每一個部分接口必須用partial關鍵詞定義,而且必須同樣的全限定名(參閱第11章命名空間和全限定名細節)。
Implementing Interfaces 實現接口
類可以實現一個接口並附帶地從一個基類派生。清單12-10包含了一個例子。
interface ICalculator { int CalculateSum(int x, int y); } class BaseCalculator { public virtual int CalculateProduct(int x, int y) { return x * y; } } class DerivedCalculator : BaseCalculator, ICalculator { public int CalculateSum(int x, int y) { return x + y; } }
在這個例子中,DerivedCalculator類派生於BaseCalculator類,並實現了ICalculator接口。在這個類的聲明中,必須首先指定基類,後跟這個類實現的接口,用逗號分隔。
提示:如果你在Visual Studio 2010中,在類的聲明中右擊這個接口的名字,你將看到「實現接口」菜單。有兩個子菜單項可用。「實現接口」菜單將生成你所選擇要實現的這個接口的所有成員。「明確實現接口」菜單將為一個明確的接口實現(本章稍後討論)做同樣的事情。
Implementing Multiple Interfaces 實現多接口
類只可以從一個單一的類派生,但它們可以實現多個接口。在這種情況下,被實現的接口放在基類之後,以逗號分隔。清單12-11含有一個例子。
interface IProductCalculator { int CalculateProduct(int x, int y); } interface ISumCalculator { int CalculateSum(int x, int y); } interface ISubtractionCalculator { int CalculateSubtraction(int x, int y); } class Calculator : IProductCalculator, ISumCalculator, ISubtractionCalculator { public int CalculateProduct(int x, int y) { return x * y; } public int CalculateSum(int x, int y) { return x + y; } public int CalculateSubtraction(int x, int y) { return x - y; } }
在這個例子中,Calculator類沒有明確的基類,但實現了三個接口。正如你期望的,類必須實現每個接口所指定的成員。
Explicitly Implementing an Interface 明確地實現一個接口
實現多接口是一個簡單的過程,但你想實現多個接口指定同一個成員除外。清單12-12含有一個例子。
interface ISumCalculator { int PerformCalculation(int x, int y); } interface IProductCalculator { int PerformCalculation(int x, int y); }
清單12-12中的兩個接口都想要實現的類面臨著一個問題。以下是實現ISumCalculator和IProductCalculator接口的一個類:
class Calculator : ISumCalculator, IProductCalculator { public int PerformCalculation(int x, int y) { //Do Something } }
問題是PerformCalculation方法應該實現哪個接口。當一個Calculator對象上溯到ISumCalculator時,調用PerformCalculation方法與對象上溯到IProductCalculator調用同樣的方法所得到的結果是不同的。
要解決這一問題,你可以使用明確的接口實現,在這裡你可以指定一個成員實現與哪個接口相關。清單12-13演示了一個明確實現清單12-12中接口的一個類。
class Calculator : ISumCalculator, IProductCalculator { int ISumCalculator.PerformCalculation(int x, int y) { Console.WriteLine("ISumCalculator.PerformCalculation was called"); return x + y; } int IProductCalculator.PerformCalculation(int x, int y) { Console.WriteLine("IProductCalculator.PerformCalculation was called"); return x * y; } }
當你明確地實現由一個接口所指定的成員時,你用與之相關的接口名作為該實現的前綴,如圖12-6所示。
當使用明確接口實現的一個類的對象上溯到一個接口類型時,.NET運行時會保證調用正確的成員實現。以下是上溯和調用PerformCalculation方法的一些語句:
class Listing_13_Test { static void Main(string[] args) { // create an instance of the Calculator object Calculator calc = new Calculator(); // upcast to IProductCalculator and call the method IProductCalculator pcalc = calc; int productResult = pcalc.PerformCalculation(10, 10); // upcast to ISumCalculator and call the method ISumCalculator scalc = calc; int sumResult = scalc.PerformCalculation(10, 10); // print the result Console.WriteLine("Product result: {0}", productResult); Console.WriteLine("Sum Result: {0}", sumResult); // wait for input before exiting Console.WriteLine("Press enter to finish"); Console.ReadLine(); } }
PerformCalculation方法的每一個明確的實現都含有一條打印出相關接口的語句。編譯並運行這些語句會產生以下結果:
IProductCalculator.PerformCalculation was called ISumCalculator.PerformCalculation was called Product result: 100 Sum Result: 20 Press enter to finish
一個接口成員的明確實現只當一個對象被上溯到這個接口類型時才是可用的。其含義是,例如,你不能在清單12-13中的類所生成的對象上調用PerformCalculation方法,直到該對象被上溯才可以。意即,Calculator類出現時是沒有成員的,直到它被上溯到一個明確實現的接口時才有成員。
Inheriting Interface Implementations 繼承接口實現
當一個基類實現一個接口時,所派生的類也實現這個接口,而且,如果基類在實現接口的成員上使用了virtual關鍵詞,派生類可以提供這些方法的自有版本。清單12-14提供了一個演示。
interface ICalculator { int CalculateSum(int x, int y); } class BaseCalc : ICalculator { public virtual int CalculateSum(int x, int y) { return x + y; } } class DerivedCalc : BaseCalc { public override int CalculateSum(int x, int y) { return base.CalculateSum(x, y) * 2; } }
在這個例子中,BaseCalc類實現了ICalculator接口,用virtual關鍵詞修改了CalculateSum方法的實現。DerivedCalc類從BaseCalc派生而來,並用oerride關鍵詞覆蓋了CalculateSum方法的基實現。
因為派生類繼承了基類的接口實現,DerivedCalc隱含地實現了ICalculator接口。以下是一些生成DerivedCalc對象,並對基類型和接口類型都作了上溯:
class Listing_14_Test { static void Main(string[] args) { // create an instance of the derived class DerivedCalc calc = new DerivedCalc(); // upcast to the base type BaseCalc bCalc = calc; // upcast the dervied type to the interface type ICalculator iCalc = calc; // call the method defined by the interface and // print out the results int result = iCalc.CalculateSum(10, 10); Console.WriteLine("Result: {0}", result); // wait for input before exiting Console.WriteLine("Press enter to finish"); Console.ReadLine(); } }
Implementing an Interface in an Abstract Class 在抽象類中實現一個接口
一個抽象類可以實現一個接口,但強制派生的類要提供這個接口所指定成員的實現。清單12-15含有一個演示。
interface ICalculator { int CalculateSum(int x, int y); int CalculateProduct(int x, int y); } abstract class AbstractCalculator : ICalculator { public abstract int CalculateSum(int x, int y); public int CalculateProduct(int x, int y) { return x * y; } }
為了強制一個派生類對接口成員提供一個實現,你只要簡單地重申這個成員的說明,添加public訪問修飾符和obstract關鍵詞。此例中的AbstractCalculator類直接實現了ICalculator接口的一個成員,並把另管委會作為抽象。從AbstractCalculator類派生的類必須對抽象方法提供一個實現,像這樣:
class Calculator : AbstractCalculator { public override int CalculateSum(int x, int y) { return x + y; } }
當抽象類實現一個接口時,從這個抽象類派生而來的類隱含地也實現這個接口,而且,從派生類生成的對象可以上溯到這個接口類型。