CLR不允許繼承多個基類,但是可以繼承多個接口。凡是能使用具名接口類型的實例的地方,都能使用實現了接口的一個類型的實例。 接口是對一組方法簽名進行了統一命名,但不提供任何實現,而具體類則必須為繼承的全部接口提供實現。
1. 定義接口
接口是用interface關鍵字定義對一組方法簽名,接口名稱一般以字母I開頭;而且還可以為接口定義事件、索引器和屬性,但禁止定義構造器和實例字段,也不能構造任何靜態成員。例如:
public interface IShout
{
public IShout();//×Error Interfaces cannot contain constructors
static void Shout1();//×Error The modifier 'static' is not valid for this item
void Shout();
string Name { get; set; }
}
2. 接口方法
具體的類繼承接口后要為接口中定義的方法提供實現。我們首先定義一個接口,然后再定義類來實現該接口。
public interface IIntroduce
{
void Shout();
void Description();
}
接口方法,即具體類中實現接口中定義的方法,它的實現要注意幾點:
- 接口方法必須是Public;
- CLR要求將接口方法標記為virtual,否則編譯器會自動標記為virtual和sealed。
public class Animal : IIntroduce
{
public void Shout() //接口方法為標記為virtual
{
Console.WriteLine("Animal Shout.");
}
public virtual void Description() //接口方法標記為virtual
{
Console.WriteLine("Animal Description.");
}
}查看IL代碼:
- 派生類可以使用New關鍵字為接口提供自己的實現。
public class Dog : Animal
{
public override void Description()//重寫基類的接口方法
{
Console.WriteLine("Dog Description!");
}
}public class Cat : Animal, IIntroduce
{
public override void Description()//重寫基類的接口方法
{
Console.WriteLine("Cat Description!");
}
new public void Shout()//重新實現接口方法
{
Console.WriteLine("Cat Shout.");
}
}
3. 顯式接口實現
實現接口有隱式實現和顯式實現兩種方式。當多個接口中包含名稱和簽名都相同的方法時,要使用顯示接口方法實現。
public interface IDemo1
class Program
{
void Func();
}
public interface IDemo2
{
void Func();
}
public class Demo : IDemo1, IDemo2
{
public void Func()
{
Console.WriteLine("Demo.Func()");
}
void IDemo1.Func()
{
Console.WriteLine("IDemo1.Func()");
}
void IDemo2.Func()
{
Console.WriteLine("IDemo2.Func()");
}
}
{
static void Main(string[] args)
{
Demo demo = new Demo();
demo.Func();//調用Demo類中的公共方法Func()
((IDemo1)demo).Func(); //顯式調用IDemo1中的Func()
((IDemo2)demo).Func(); //顯式調用IDemo2中的Func()
Console.Read();
}
}
調用結果:
顯式接口實現要注意:
- 不允許指定訪問性,如Public等;查看元數據時會發現它自動標記為Private。
- 不能標記為virtual。
- 顯式接口應該慎重使用,因為值類型的實例在轉型為接口時會發生裝箱,而且顯式接口方法不能被派生類繼承。
4.泛型接口
FCL提供了很多現成的接口如IComparable,同時提供了其泛型接口形式IComparable<T>.這樣做能夠編譯時就檢測類型從而提高了類型安全,而且減少了參數向object類型轉換的裝箱拆箱操作,提高了性能。
int x = 1;
IComparable y = "2";
y.CompareTo(x); //編譯通過,運行時錯誤
IComparable<int> z = 3;
z.CompareTo(x); //編譯通過,運行通過
5. 基類vs接口
- 如果存在IS-A關系使用基類,存在CAN-DO關系,使用接口。
- 基類實現較容易一些,基類提供的功能派生類一般稍作改動即可;而接口方法則要實現所有成員。
- 版本控制:向基類添加新方法后派生類可以直接使用;向接口添加新方法后需要修改源代碼並重新編譯。
你也許喜歡:跟小靜讀CLR via C#(00)-開篇及目錄