接口(interface)
接口(interface)定义了一个可由类和结构实现的协定。接口可以包含方法、属性、事件和索引器。接口不提供它所定义的成员的实现-它仅指定实现该接口的类或结构必须提供的成员。
è 一个接口声明可以声明零个或多个成员。
è 接口的成员必须是方法、属性、事件或索引器。
è 接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型,也不能包含任何种类的静态成员。
è 所有接口成员都隐式地具有public访问属性。
è 接口成员声明中包含任何修饰符都属于编译时错误。具体来说,不使用修饰符abstract、public、protected、internal、private、virtual、override或static来声明接口成员。
完全限定接口成员名:
接口成员有时也用它的完全限定名(fully qualified name)来引用。接口成员的完全限定名是这样组成的:声明该成员的接口的名称,后跟一个点,再后跟该成员的名称。成员的完全限定名将引用声明该成员的接口。
显式接口成员实现:
为了实现接口,类或结构可以声明显式接口成员实现(explicit interface member implementation) 显式接口成员实现就是一种方法、属性、事件或索引器声明,它使用完全限定接口成员名称作为标识符。
显式接口成员实现有两个主要用途:
->由于显式接口成员实现不能通过类或结构实例来访问,因此它们就不属于类或结构的自身的公共接口。当需在一个公用的类或结构中实现一些仅供内部使用(不允许外界访问)的接口时,这就特别有用。
->显式接口成员实现可以消除因同时含有多个相同签名的接口成员所引起的多义性。如果没有显式接口成员实现,一个类或结构就不可能为具有相同签名和返回类型的接口成员分别提供相应的实现,也不可能为具有相同签名和不同返回类型的所有接口成员中的任何一个提供实现。
->在方法调用、属性访问或索引器访问中,不能直接访问“显式接口成员实现”的成员,即使用它的完全限定名也不行。“显式接口成员实现”的成员只能通过接口实例访问,并且在通过接口实例访问时,只能用该接口成员的简单名称来引用。
->显式接口成员实现中包含访问修饰符属于编译时错误,而且如果包含abstract、virtual、override或static修饰符也属于编译时错误。
->显式接口成员实现具有与其它成员不同的可访问性特征。由于显式接口成员实现永远不能在方法调用或属性访问中通过它们的完全限定名来访问,因此,它们似乎是private(私有的)。但是,因为它们可以通过接口实例来访问,所以它们似乎又是public(公共的)。
接口的多继承:
看一段代码:
using System ;
interface IA
{
void F();
}
interface IB:IA{
new void F();
}
interface IC:IA
{
void G();
}
interface IBC: IB,IC
{
}
class Derive:IBC
{
public void F()
{
Console .WriteLine ("IB.F()");
}
public void G()
{
Console .WriteLine ("IC.G()");
}
}
class Test
{
static void Main()
{
Derive d=new Derive();
d.F();
((IA)d).F();
((IB)d).F();
((IC)d).F();
((IBC)d).F();
}
}
输出: IB.F()
IB.F()
IB.F()
IB.F()
IB.F()
接口的重新实现:
->一个类若继承了某个接口的实现,则只要将该接口列入它的基类列表中,就可以重新实现该接口。
->接口的重新实现与接口的初始实现遵循完全相同的接口映射规则。因此,继承的接口映射不会对为重新实现该接口而建立的接口映射产生任何影响。
看一段代码:
using System ;
interface IA
{
void F();
}
class B:IA
{
void IA.F() //显式接口实现
{
Console .WriteLine ("B.F");
}
}
class C:B,IA
{
public void F()
{
Console .WriteLine ("C.F");
}
}
class Test
{
static void Main()
{
C c=new C ();
((IA)c).F();
}
}
输出:C.F
接口与抽象类:
1. 类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类。接口只是一个行为的规范或规定。接口表述的是“我能做”(Can-do),抽象类更多的是定义在一系列紧密相关的类间(Is-a),而接口大多数是关系疏松但都实现某一功能的类中。
2. 接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;
3. 一个类一次可以实现若干个接口,但是只能扩展一个父类;
4. 抽象类实现了OOP中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义不可变的,而把可变的由子类去实现;
5. 好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。
6. 如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法。
接口与抽象类:
1. 抽象类用于部分实现一个类,再由用户按需求对其进行不同的扩展和完善;接口只是定义一个行为的规范或规定。
2. 抽象类在组件的所有实现间提供通用的已实现功能;接口创建在大范围全异对象间使用的功能。
3. 抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。
4. 抽象类主要用于设计大的功能单元;而接口用于设计小而简练的功能块。
接口:
定义:接口就是语义相关的一个或多个抽象成员组成的命名集合。接口表示的是指定的类或结构需要支持的行为。
->接口包含的成员不带访问修饰符(因为所有接口成员都隐式规定为公共(public)和抽象(abstract)的。
->所有在接口中定义的成员都必须在要实现它的类或结构中实现。
接口与抽象类的对比:
->相同点: 当一个类派生自抽象基类时, 它必须实现抽象方法的细节(倘若派生类没有声明为抽象的)
->不同点: 抽象基类不只能够定义一组抽象方法,还可以指定公用的、私有的和受保护的状态数据以及许多可被子类访问的实体方法。
如何动态判断一个类型支持哪些接口?
1. 显式强制转换: IPointy a =( IPointy)b; 需要使用结构化异常处理;不推荐。
2. as关键字(获取接口引用):可以在使用该关键字的语句中得到指向该对象接口的引用;否则,将返回一个值为null的空引用。
IPointy a = b as IPointy; if(a!=null) { } else { }
3. is关键字(获取接口引用): 如果要考察的对象与指定接口不符,将返回false值。
If ( b is IPointy) { } else { }
显式接口实现:
->不能在定义显式实现成员时加访问修饰符。