1.接口概述
接口可以是命名空间或类的成员,并且可以包含下列成员的签名:
一个接口可从一个或多个基接口继承。
接口不能包含字段。接口成员一定是公共的。
类和结构可以像类继承基类或结构一样从接口继承,但有两个例外:
-
类或结构可继承多个接口。
-
当类或结构继承接口时,它继承成员定义但不继承实现。
当基类型列表包含基类和接口时,基类必须是列表中的第一项。
实现接口的类可以显式实现该接口的成员。显式实现的成员不能通过类实例访问,而只能通过接口实例访问
接口具有下列属性:
-
接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员。
-
不能直接实例化接口。
-
接口可以包含事件、索引器、方法和属性。
-
接口不包含方法的实现。
-
类和结构可从多个接口继承。
-
接口自身可从多个接口继承。
2
当类或结构实现某个特定接口时,该类或结构的实例可以隐式地转换为该接口类型。例如
EditBox editBox = new EditBox();
IControl control = editBox;
IDataBound dataBound = editBox;
在无法静态知道某个实例是否实现某个特定接口的情况下,可以使用动态类型强制转换。例如,下面的语句使用动态类型强制转换获得对象的 IControl 和 IDataBound 接口实现。由于该对象的实际类型为 EditBox,此强制转换成功。
object obj = new EditBox();
IControl control = (IControl)obj;
IDataBound dataBound = (IDataBound)obj;
3
如果类实现两个接口,并且这两个接口包含具有相同签名的成员,那么在类中实现该成员将导致两个接口都使用该成员作为它们的实现。例如:
C# | |
---|---|
interface IControl { void Paint(); } interface ISurface { void Paint(); } class SampleClass : IControl, ISurface { // Both ISurface.Paint and IControl.Paint call this method. public void Paint() { } } |
然而,如果两个接口成员执行不同的函数,那么这可能会导致其中一个接口的实现不正确或两个接口的实现都不正确。可以显式地实现接口成员 -- 即创建一个仅通过该接口调用并且特定于该接口的类成员。这是使用接口名称和一个句点命名该类成员来实现的。例如:
C# | |
---|---|
public class SampleClass : IControl, ISurface { void IControl.Paint() { System.Console.WriteLine("IControl.Paint"); } void ISurface.Paint() { System.Console.WriteLine("ISurface.Paint"); } } |
类成员 IControl.Paint 只能通过 IControl 接口使用,ISurface.Paint 只能通过 ISurface 使用。两个方法实现都是分离的,都不可以直接在类中使用。例如:
C# | 复制代码 |
---|---|
SampleClass obj = new SampleClass(); //obj.Paint(); // Compiler error. IControl c = (IControl)obj; c.Paint(); // Calls IControl.Paint on SampleClass. ISurface s = (ISurface)obj; s.Paint(); // Calls ISurface.Paint on SampleClass. |
显式实现还用于解决两个接口分别声明具有相同名称的不同成员(如属性和方法)的情况:
C# | 复制代码 |
---|---|
interface ILeft { int P { get;} } interface IRight { int P(); } |
为了同时实现两个接口,类必须对属性 P 和/或方法 P 使用显式实现以避免编译器错误。例如:
C# | 复制代码 |
---|---|
class Middle : ILeft, IRight { public int P() { return 0; } int ILeft.P { get { return 0; } } |