【轉】基於C#的接口基礎教程之五(4)
4、映射接口
類必須爲在基類表中列出的所有接口的成員提供具體的實現。在類中定位接口成員的實現稱之爲接口映射(interface mapping )。
映射,數學上表示一一對應的函數關係。接口映射的含義也是一樣,接口通過類來實現,那麼對於在接口中定義的每一個成員,都應該對應着類的一個成員來爲它提供具體的實現。
類的成員及其所映射的接口成員之間必須滿足下列條件:
1、如果A和B都是成員方法,那麼A和B的名稱、類型、形參表(包括參數個數和每一個參數的類型)都應該是一致的。
2、如果A和B都是屬性,那麼A和B的名稱、類型應當一致,而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。
3、如果A和B都是時間那麼A和B的名稱、類型應當一致。
4、如果A和B都是索引指示器,那麼A和B的類型、形參表(包括參數個數和每一個參數的類型)應當一致。而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。
那麼,對於一個接口成員,怎樣確定由哪一個類的成員來實現呢?即一個接口成員映射的是哪一個類的成員?在這裏,我們敘述一下接口映射的過程。假設類C 實現了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來實現接口成員Member,即Member的映 射過程是這樣的:
1、如果C中存在着一個顯式接口成員執行體,該執行體與接口IInterface 及其成員Member相對應,則由它來實現Member 成員。
2、如果條件(1)不滿足,且C中存在着一個非靜態的公有成員,該成員與接口成員Member相對應,則由它來實現Member 成員。
3、如果上述條件仍不滿足,則在類C定義的基類列表中尋找一個C 的基類D,用D來代替C。
4、重複步驟1-- 3 ,遍歷C的所有直接基類和非直接基類,直到找到一個滿足條件的類的成員。
5、如果仍然沒有找到,則報告錯誤。
下面是一個調用基類方法來實現接口成員的例子。類Class2 實現了接口Interface1,類Class2 的基類Class1 的成員也參與了接口的映射,也就是說類Class2 在對接口Interface1進行實現時,使用了類Class1提供的成員方法F來實現接口Interface1的成員方法F:
interface Interface1 {
void F( ) ;
}
class Class1 {
public void F( ) { }
public void G( ) { }
}
class Class2: Class1, Interface1 {
new public void G( ) {}
}
注意:接口的成員包括它自己定義的成員,而且包括該接口所有父接口定義的成員。在接口映射時,不僅要對接口定義體中顯式定義的所有成員進行映射,而且要對隱式地從父接口那裏繼承來的所有接口成員進行映射。
在進行接口映射時,還要注意下面兩點:
1、在決定由類中的哪個成員來實現接口成員時,類中顯式說明的接口成員比其它成員優先實現。
2、使用Private、protected和static修飾符的成員不能參與實現接口映射。例如:
interface ICloneable {
object Clone( ) ;
}
class C: ICloneable {
object ICloneable.Clone( ) {…}
public object Clone( ) {…}
}
例子中成員ICloneable.Clone 稱爲接口ICloneable 的成員Clone 的實現者,因爲它是顯式說明的接口成員,比其它成員有着更高的優先權。
如果一個類實現了兩個或兩個以上名字、類型和參數類型都相同的接口,那麼類中的一個成員就可能實現所有這些接口成員:
interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void Paint( ) {…}
}
這裏,接口IControl和IForm的方法Paint都映射到了類Page中的Paint方法。當然也可以分別用顯式的接口成員分別實現這兩個方法:
interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void IControl.Paint( ) {
//具體的接口實現代碼
}
public void IForm.Paint( ) {
//具體的接口實現代碼
}
}
上面的兩種寫法都是正確的。但是如果接口成員在繼承中覆蓋了父接口的成員,那麼對該接口成員的實現就可能必須映射到顯式接口成員執行體。看下面的例子:
interface IBase {
int P { get; }
}
interface IDerived: IBase {
new int P( ) ;
}
接口IDerived從接口IBase中繼承,這時接口IDerived 的成員方法覆蓋了父接口的成員方法。因爲這時存在着同名的兩個接口成員,那麼對這兩個接口成員的實現如果不採用顯式接口成員執行體,編譯器將無法分辨接口 映射。所以,如果某個類要實現接口IDerived,在類中必須至少定義一個顯式接口成員執行體。採用下面這些寫法都是合理的:
//一:對兩個接口成員都採用顯式接口成員執行體來實現
lass C: IDerived {
int IBase.P
get
{ //具體的接口實現代碼 }
int IDerived.P( ){
//具體的接口實現代碼 }
}
//二:對Ibase 的接口成員採用顯式接口成員執行體來實現
class C: IDerived {
int IBase.P
get {//具體的接口實現代碼}
public int P( ){
//具體的接口實現代碼 }
}
//三:對IDerived 的接口成員採用顯式接口成員執行體來實現
class C: IDerived{
public int P
get {//具體的接口實現代碼}
int IDerived.P( ){
//具體的接口實現代碼}
}
另一種情況是,如果一個類實現了多個接口,這些接口又擁有同一個父接口,這個父接口只允許被實現一次。
using System ;
interface IControl {
void Paint( ) ;
interface ITextBox: IControl {
void SetText(string text) ;
}
interface IListBox: IControl {
void SetItems(string[] items) ;
}
class ComboBox: IControl, ITextBox, IListBox {
void IControl.Paint( ) {…}
void ITextBox.SetText(string text) {…}
void IListBox.SetItems(string[] items) {…}
}
上面的例子中,類ComboBox實現了三個接口:IControl,ITextBox和IListBox。如果認爲ComboBox不僅實現了 IControl接口,而且在實現ITextBox和IListBox的同時,又分別實現了它們的父接口IControl。實際上,對接口 ITextBox 和IListBox 的實現,分享了對接口IControl 的實現。
我們對C#的接口有了較全面的認識,基本掌握了怎樣應用C#的接口編程,但事實上,C#的不僅僅應用於.NET平臺,它同樣支持以前的COM,可以實現COM類到.NET類的轉換,如C#調用API。欲瞭解這方面的知識,請看下一節-接口轉換。
員?在這裏,我們敘述一下接口映射的過程。假設類C 實現了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來實現接口成員Member,即Member的映 射過程是這樣的:
1、如果C中存在着一個顯式接口成員執行體,該執行體與接口IInterface 及其成員Member相對應,則由它來實現Member 成員。
2、如果條件(1)不滿足,且C中存在着一個非靜態的公有成員,該成員與接口成員Member相對應,則由它來實現Member 成員。
3、如果上述條件仍不滿足,則在類C定義的基類列表中尋找一個C 的基類D,用D來代替C。
4、重複步驟1-- 3 ,遍歷C的所有直接基類和非直接基類,直到找到一個滿足條件的類的成員。
5、如果仍然沒有找到,則報告錯誤。
下面是一個調用基類方法來實現接口成員的例子。類Class2 實現了接口Interface1,類Class2 的基類Class1 的成員也參與了接口的映射,也就是說類Class2 在對接口Interface1進行實現時,使用了類Class1提供的成員方法F來實現接口Interface1的成員方法F:
interface Interface1 {
void F( ) ;
}
class Class1 {
public void F( ) { }
public void G( ) { }
}
class Class2: Class1, Interface1 {
new public void G( ) {}
}
注意:接口的成員包括它自己定義的成員,而且包括該接口所有父接口定義的成員。在接口映射時,不僅要對接口定義體中顯式定義的所有成員進行映射,而且要對隱式地從父接口那裏繼承來的所有接口成員進行映射。
類必須爲在基類表中列出的所有接口的成員提供具體的實現。在類中定位接口成員的實現稱之爲接口映射(interface mapping )。
映射,數學上表示一一對應的函數關係。接口映射的含義也是一樣,接口通過類來實現,那麼對於在接口中定義的每一個成員,都應該對應着類的一個成員來爲它提供具體的實現。
類的成員及其所映射的接口成員之間必須滿足下列條件:
1、如果A和B都是成員方法,那麼A和B的名稱、類型、形參表(包括參數個數和每一個參數的類型)都應該是一致的。
2、如果A和B都是屬性,那麼A和B的名稱、類型應當一致,而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。
3、如果A和B都是時間那麼A和B的名稱、類型應當一致。
4、如果A和B都是索引指示器,那麼A和B的類型、形參表(包括參數個數和每一個參數的類型)應當一致。而且A和B的訪問器也是類似的。但如果A不是顯式接口成員執行體,A允許增加自己的訪問器。
那麼,對於一個接口成員,怎樣確定由哪一個類的成員來實現呢?即一個接口成員映射的是哪一個類的成員?在這裏,我們敘述一下接口映射的過程。假設類C 實現了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來實現接口成員Member,即Member的映 射過程是這樣的:
1、如果C中存在着一個顯式接口成員執行體,該執行體與接口IInterface 及其成員Member相對應,則由它來實現Member 成員。
2、如果條件(1)不滿足,且C中存在着一個非靜態的公有成員,該成員與接口成員Member相對應,則由它來實現Member 成員。
3、如果上述條件仍不滿足,則在類C定義的基類列表中尋找一個C 的基類D,用D來代替C。
4、重複步驟1-- 3 ,遍歷C的所有直接基類和非直接基類,直到找到一個滿足條件的類的成員。
5、如果仍然沒有找到,則報告錯誤。
下面是一個調用基類方法來實現接口成員的例子。類Class2 實現了接口Interface1,類Class2 的基類Class1 的成員也參與了接口的映射,也就是說類Class2 在對接口Interface1進行實現時,使用了類Class1提供的成員方法F來實現接口Interface1的成員方法F:
interface Interface1 {
void F( ) ;
}
class Class1 {
public void F( ) { }
public void G( ) { }
}
class Class2: Class1, Interface1 {
new public void G( ) {}
}
注意:接口的成員包括它自己定義的成員,而且包括該接口所有父接口定義的成員。在接口映射時,不僅要對接口定義體中顯式定義的所有成員進行映射,而且要對隱式地從父接口那裏繼承來的所有接口成員進行映射。
在進行接口映射時,還要注意下面兩點:
1、在決定由類中的哪個成員來實現接口成員時,類中顯式說明的接口成員比其它成員優先實現。
2、使用Private、protected和static修飾符的成員不能參與實現接口映射。例如:
interface ICloneable {
object Clone( ) ;
}
class C: ICloneable {
object ICloneable.Clone( ) {…}
public object Clone( ) {…}
}
例子中成員ICloneable.Clone 稱爲接口ICloneable 的成員Clone 的實現者,因爲它是顯式說明的接口成員,比其它成員有着更高的優先權。
如果一個類實現了兩個或兩個以上名字、類型和參數類型都相同的接口,那麼類中的一個成員就可能實現所有這些接口成員:
interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void Paint( ) {…}
}
這裏,接口IControl和IForm的方法Paint都映射到了類Page中的Paint方法。當然也可以分別用顯式的接口成員分別實現這兩個方法:
interface IControl {
void Paint( ) ;
}
interface IForm {
void Paint( ) ;
}
class Page: IControl, IForm {
public void IControl.Paint( ) {
//具體的接口實現代碼
}
public void IForm.Paint( ) {
//具體的接口實現代碼
}
}
上面的兩種寫法都是正確的。但是如果接口成員在繼承中覆蓋了父接口的成員,那麼對該接口成員的實現就可能必須映射到顯式接口成員執行體。看下面的例子:
interface IBase {
int P { get; }
}
interface IDerived: IBase {
new int P( ) ;
}
接口IDerived從接口IBase中繼承,這時接口IDerived 的成員方法覆蓋了父接口的成員方法。因爲這時存在着同名的兩個接口成員,那麼對這兩個接口成員的實現如果不採用顯式接口成員執行體,編譯器將無法分辨接口 映射。所以,如果某個類要實現接口IDerived,在類中必須至少定義一個顯式接口成員執行體。採用下面這些寫法都是合理的:
//一:對兩個接口成員都採用顯式接口成員執行體來實現
lass C: IDerived {
int IBase.P
get
{ //具體的接口實現代碼 }
int IDerived.P( ){
//具體的接口實現代碼 }
}
//二:對Ibase 的接口成員採用顯式接口成員執行體來實現
class C: IDerived {
int IBase.P
get {//具體的接口實現代碼}
public int P( ){
//具體的接口實現代碼 }
}
//三:對IDerived 的接口成員採用顯式接口成員執行體來實現
class C: IDerived{
public int P
get {//具體的接口實現代碼}
int IDerived.P( ){
//具體的接口實現代碼}
}
另一種情況是,如果一個類實現了多個接口,這些接口又擁有同一個父接口,這個父接口只允許被實現一次。
using System ;
interface IControl {
void Paint( ) ;
interface ITextBox: IControl {
void SetText(string text) ;
}
interface IListBox: IControl {
void SetItems(string[] items) ;
}
class ComboBox: IControl, ITextBox, IListBox {
void IControl.Paint( ) {…}
void ITextBox.SetText(string text) {…}
void IListBox.SetItems(string[] items) {…}
}
上面的例子中,類ComboBox實現了三個接口:IControl,ITextBox和IListBox。如果認爲ComboBox不僅實現了 IControl接口,而且在實現ITextBox和IListBox的同時,又分別實現了它們的父接口IControl。實際上,對接口 ITextBox 和IListBox 的實現,分享了對接口IControl 的實現。
我們對C#的接口有了較全面的認識,基本掌握了怎樣應用C#的接口編程,但事實上,C#的不僅僅應用於.NET平臺,它同樣支持以前的COM,可以實現COM類到.NET類的轉換,如C#調用API。欲瞭解這方面的知識,請看下一節-接口轉換。
員?在這裏,我們敘述一下接口映射的過程。假設類C 實現了一個接口IInterface,Member是接口IInterface中的一個成員,在定位由誰來實現接口成員Member,即Member的映 射過程是這樣的:
1、如果C中存在着一個顯式接口成員執行體,該執行體與接口IInterface 及其成員Member相對應,則由它來實現Member 成員。
2、如果條件(1)不滿足,且C中存在着一個非靜態的公有成員,該成員與接口成員Member相對應,則由它來實現Member 成員。
3、如果上述條件仍不滿足,則在類C定義的基類列表中尋找一個C 的基類D,用D來代替C。
4、重複步驟1-- 3 ,遍歷C的所有直接基類和非直接基類,直到找到一個滿足條件的類的成員。
5、如果仍然沒有找到,則報告錯誤。
下面是一個調用基類方法來實現接口成員的例子。類Class2 實現了接口Interface1,類Class2 的基類Class1 的成員也參與了接口的映射,也就是說類Class2 在對接口Interface1進行實現時,使用了類Class1提供的成員方法F來實現接口Interface1的成員方法F:
interface Interface1 {
void F( ) ;
}
class Class1 {
public void F( ) { }
public void G( ) { }
}
class Class2: Class1, Interface1 {
new public void G( ) {}
}
注意:接口的成員包括它自己定義的成員,而且包括該接口所有父接口定義的成員。在接口映射時,不僅要對接口定義體中顯式定義的所有成員進行映射,而且要對隱式地從父接口那裏繼承來的所有接口成員進行映射。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.