c#的接口详解
什么是接口?其實,接口簡單理解就是一種約定,使得實現接口的類或結構在形式上保持一致。個人覺得,使用接口可以使程序更加清晰和條理化,這就是接口的好處,但并不是所有的編程語言都支持接口,C#是支持接口的。注意,雖然在概念上,C#接口類似于COM接口,但他們的底層結構是不同的。那么,我們來看一下如何聲明和使用接口。
聲明接口
聲明接口在語法上和聲明抽象類完全相同,例如這里有一個銀行賬戶的接口:
public?interface?IBankAccount
{
????void?PayIn(decimal?amount);
????bool?Withdraw(decimal?amount);
????decimal?Balance
????{
????????get;
????}
}
注意:接口中只能包含方法、屬性、索引器和事件的聲明。不允許聲明成員上的修飾符,即使是pubilc都不行,因為接口成員總是公有的,也不能聲明為虛擬和靜態的。如果需要修飾符,最好讓實現類來聲明。
使用接口的例子
這是書上的一個簡單的例子,但足以說明接口的使用方法。
一個銀行賬戶的接口,兩個不同銀行賬戶的實現類,都繼承于這個接口。接口聲明如上。下面是兩個賬戶類:
class?SaverAccount?:?IBankAccount
{
????private?decimal?balance;
????public?decimal?Balance
????{
????????get?
????????{
????????????return?balance;????
????????}
????}
????public?void?PayIn(decimal?amount)
????{
????????balance?+=?amount;
????}
????public?bool?Withdraw(decimal?amount)
????{
????????if?(balance?>=?amount)
????????{
????????????balance?-=?amount;
????????????return?true;
????????}
????????Console.WriteLine("Withdraw?failed.");
????????return?false;
????}
????public?override?string?ToString()
????{
????????return?String.Format("Venus?Bank?Saver:Balance={0,6:C}",?balance);
????}
}
class?GoldAccount?:?IBankAccount
{
????private?decimal?balance;
????public?decimal?Balance
????{
????????get?
????????{
????????????return?balance;
????????}
????}
????public?void?PayIn(decimal?amount)
????{
????????balance?+=?amount;
????}
????public?bool?Withdraw(decimal?amount)
????{
????????if?(balance?>=?amount)
????????{
????????????balance?-=?amount;
????????????return?true;
????????}
????????Console.WriteLine("Withdraw?failed.");
????????return?false;
????}
????public?override?string?ToString()
????{
????????return?String.Format("Jupiter?Bank?Saver:Balance={0,6:C}",?balance);
????}
}
可見,這兩個實現類多繼承了IBankAccount接口,因此它們必須要實現接口中的所有聲明的方法。要不然,編譯就會出錯。讓我們來測試一下,下面是測試代碼:
static?void?Main(string[]?args)
{
????IBankAccount?venusAccount?=?new?SaverAccount();
????IBankAccount?jupiterAccount?=?new?CurrentAccount();
????venusAccount.PayIn(200);
????jupiterAccount.PayIn(500);
????Console.WriteLine(venusAccount.ToString());
????jupiterAccount.PayIn(400);
????jupiterAccount.Withdraw(500);
????jupiterAccount.Withdraw(100);
????Console.WriteLine(jupiterAccount.ToString());
}
請注意開頭兩句,我們把它們聲明為IBankAccount引用的方式,而沒有聲明為類的引用,為什么呢?因為,這樣我們就可以讓它指向執行這個接口的任何類的實例了,比較靈活。但這也有個缺點,如果我們要執行不屬于接口的方法,比如這里重載的ToString()方法,就要先把接口的引用強制轉換成合適的類型了。
接口的繼承
接口也可以彼此繼承,就象類的繼承一樣。比如我們又聲明一個接口ITransferBankAccount,它繼承于IBankAccount接口。
interface?ITransferBankAccount?:?IBankAccount?
{
????bool?TransferTo(IBankAccount?destination,?decimal?amount);
}
在這個接口中,又新增加了一個方法TransferTo(),所以如果我們要寫一個類從ITransferBankAccount繼承的話,就必須要實現IBankAccount和ITransferBankAccount兩個接口所有的方法聲明。即:
class?CurrentAccount?:?ITransferBankAccount
{
????private?decimal?balance;
????public?decimal?Balance
????{
????????get
????????{
????????????return?balance;
????????}
????}
????public?void?PayIn(decimal?amount)
????{
????????balance?+=?amount;
????}
????public?bool?Withdraw(decimal?amount)
????{
????????if?(balance?>=?amount)
????????{
????????????balance?-=?amount;
????????????return?true;
????????}
????????Console.WriteLine("Withdraw?failed.");
????????return?false;
????}
????public?override?string?ToString()
????{
????????return?String.Format("Jupiter?Bank?Saver:Balance={0,6:C}",?balance);
????}
????public?bool?TransferTo(IBankAccount?destination,?decimal?amount)
????{
????????if?(Withdraw(amount))
????????{
????????????destination.PayIn(amount);
????????????return?true;
????????}
????????else
????????{?
????????????return?false;
????????}
????}
}
總結起來說,使用C#接口應注意幾個問題:
聲明接口
聲明接口在語法上和聲明抽象類完全相同,例如這里有一個銀行賬戶的接口:
public?interface?IBankAccount
{
????void?PayIn(decimal?amount);
????bool?Withdraw(decimal?amount);
????decimal?Balance
????{
????????get;
????}
}
注意:接口中只能包含方法、屬性、索引器和事件的聲明。不允許聲明成員上的修飾符,即使是pubilc都不行,因為接口成員總是公有的,也不能聲明為虛擬和靜態的。如果需要修飾符,最好讓實現類來聲明。
使用接口的例子
這是書上的一個簡單的例子,但足以說明接口的使用方法。
一個銀行賬戶的接口,兩個不同銀行賬戶的實現類,都繼承于這個接口。接口聲明如上。下面是兩個賬戶類:
class?SaverAccount?:?IBankAccount
{
????private?decimal?balance;
????public?decimal?Balance
????{
????????get?
????????{
????????????return?balance;????
????????}
????}
????public?void?PayIn(decimal?amount)
????{
????????balance?+=?amount;
????}
????public?bool?Withdraw(decimal?amount)
????{
????????if?(balance?>=?amount)
????????{
????????????balance?-=?amount;
????????????return?true;
????????}
????????Console.WriteLine("Withdraw?failed.");
????????return?false;
????}
????public?override?string?ToString()
????{
????????return?String.Format("Venus?Bank?Saver:Balance={0,6:C}",?balance);
????}
}
class?GoldAccount?:?IBankAccount
{
????private?decimal?balance;
????public?decimal?Balance
????{
????????get?
????????{
????????????return?balance;
????????}
????}
????public?void?PayIn(decimal?amount)
????{
????????balance?+=?amount;
????}
????public?bool?Withdraw(decimal?amount)
????{
????????if?(balance?>=?amount)
????????{
????????????balance?-=?amount;
????????????return?true;
????????}
????????Console.WriteLine("Withdraw?failed.");
????????return?false;
????}
????public?override?string?ToString()
????{
????????return?String.Format("Jupiter?Bank?Saver:Balance={0,6:C}",?balance);
????}
}
可見,這兩個實現類多繼承了IBankAccount接口,因此它們必須要實現接口中的所有聲明的方法。要不然,編譯就會出錯。讓我們來測試一下,下面是測試代碼:
static?void?Main(string[]?args)
{
????IBankAccount?venusAccount?=?new?SaverAccount();
????IBankAccount?jupiterAccount?=?new?CurrentAccount();
????venusAccount.PayIn(200);
????jupiterAccount.PayIn(500);
????Console.WriteLine(venusAccount.ToString());
????jupiterAccount.PayIn(400);
????jupiterAccount.Withdraw(500);
????jupiterAccount.Withdraw(100);
????Console.WriteLine(jupiterAccount.ToString());
}
請注意開頭兩句,我們把它們聲明為IBankAccount引用的方式,而沒有聲明為類的引用,為什么呢?因為,這樣我們就可以讓它指向執行這個接口的任何類的實例了,比較靈活。但這也有個缺點,如果我們要執行不屬于接口的方法,比如這里重載的ToString()方法,就要先把接口的引用強制轉換成合適的類型了。
接口的繼承
接口也可以彼此繼承,就象類的繼承一樣。比如我們又聲明一個接口ITransferBankAccount,它繼承于IBankAccount接口。
interface?ITransferBankAccount?:?IBankAccount?
{
????bool?TransferTo(IBankAccount?destination,?decimal?amount);
}
在這個接口中,又新增加了一個方法TransferTo(),所以如果我們要寫一個類從ITransferBankAccount繼承的話,就必須要實現IBankAccount和ITransferBankAccount兩個接口所有的方法聲明。即:
class?CurrentAccount?:?ITransferBankAccount
{
????private?decimal?balance;
????public?decimal?Balance
????{
????????get
????????{
????????????return?balance;
????????}
????}
????public?void?PayIn(decimal?amount)
????{
????????balance?+=?amount;
????}
????public?bool?Withdraw(decimal?amount)
????{
????????if?(balance?>=?amount)
????????{
????????????balance?-=?amount;
????????????return?true;
????????}
????????Console.WriteLine("Withdraw?failed.");
????????return?false;
????}
????public?override?string?ToString()
????{
????????return?String.Format("Jupiter?Bank?Saver:Balance={0,6:C}",?balance);
????}
????public?bool?TransferTo(IBankAccount?destination,?decimal?amount)
????{
????????if?(Withdraw(amount))
????????{
????????????destination.PayIn(amount);
????????????return?true;
????????}
????????else
????????{?
????????????return?false;
????????}
????}
}
總結起來說,使用C#接口應注意幾個問題:
1、C#中的接口是獨立于類來定義的。這與 C++模型是對立的,在 C++中接口實際上就是抽象基類。
2、接口和類都可以繼承多個接口。
3、類可以繼承一個基類,接口根本不能繼承類。這種模型避免了 C++的多繼承問題,C++中不同基類中的實現可能出現沖突。因此也不再需要諸如虛擬繼承和顯式作用域這類復雜機制。C#的簡化接口模型有助于加快應用程序的開發。
4、一個接口定義一個只有抽象成員的引用類型。C#中一個接口實際所做的,僅僅只存在著方法標志,但根本就沒有執行代碼。這就暗示了不能實例化一個接口,只能實例化一個派生自該接口的對象。
5、接口可以定義方法、屬性和索引。所以,對比一個類,接口的特殊性是:當定義一個類時,可以派生自多重接口,而你只能可以從僅有的一個類派生。
總結
- 上一篇: AMD院士站台 异构计算与OpenCL编
- 下一篇: c# char unsigned_dll