C#接口.docx
- 文档编号:5255325
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:22
- 大小:24.32KB
C#接口.docx
《C#接口.docx》由会员分享,可在线阅读,更多相关《C#接口.docx(22页珍藏版)》请在冰豆网上搜索。
C#接口
.接口269
13.1接口声明269
13.1.1接口修饰符269
13.1.2基接口269
13.1.3接口体270
13.2接口成员270
13.2.1接口方法271
13.2.2接口属性272
13.2.3接口事件272
13.2.4接口索引器272
13.2.5接口成员访问272
13.3完全限定接口成员名274
13.4接口实现275
13.4.1显式接口成员实现275
13.4.2接口映射277
13.4.3接口实现继承280
13.4.4接口重新实现281
13.4.5抽象类和接口282
1.接口
一个接口定义一个协定。
实现某接口的类或结构必须遵守该接口定义的协定。
一个接口可以从多个基接口继承,而一个类或结构可以实现多个接口。
接口可以包含方法、属性、事件和索引器。
接口本身不提供它所定义的成员的实现。
接口只指定实现该接口的类或结构必须提供的成员。
1.1接口声明
interface-declaration是用于声明新的接口类型的type-declaration(第9.5节)。
interface-declaration:
attributesoptinterface-modifiersoptinterfaceidentifierinterface-baseoptinterface-body;opt
interface-declaration由下列项组成:
一个可选的attributes集(第17节),后跟一个可选的interface-modifiers集(第13.1.1节),后面再跟关键字interface和命名接口的identifier,还可根据需要后跟可选的interface-base规范(第13.1.2节),再后跟interface-body(第13.1.3节),还可选择后跟一个分号。
1.1.1接口修饰符
interface-declaration可以根据需要包含一个接口修饰符序列:
interface-modifiers:
interface-modifier
interface-modifiersinterface-modifier
interface-modifier:
new
public
protected
internal
private
同一修饰符在一个接口声明中出现多次属于编译时错误。
new修饰符仅允许在类中定义的接口中使用。
它指定接口隐藏同名的继承成员,详见第10.2.2节中的介绍。
public、protected、internal和private修饰符控制接口的可访问性。
根据接口声明所在的上下文,只允许使用这些修饰符中的一部分(第3.5.1节)。
1.1.2基接口
接口可以从零个或多个接口继承,被继承的接口称为该接口的显式基接口(explicitbaseinterface)。
当接口具有一个或多个显式基接口时,在该接口声明中,接口标识符后就要紧跟一个冒号以及一个由逗号分隔的基接口标识符列表。
interface-base:
:
interface-type-list
接口的显式基接口必须至少与接口本身具有同样的可访问性(第3.5.4节)。
例如,在public接口的interface-base中指定private或internal接口就是一个编译时错误。
接口不能从自身直接或间接继承,否则会发生编译时错误。
接口的基接口(baseinterface)包括显式基接口,以及这些显式基接口的基接口。
换言之,基接口集是显式基接口、它们的显式基接口(依此类推)的完全可传递的闭包。
接口继承其基接口的所有成员。
在下面的示例中
interfaceIControl
{
voidPaint();
}
interfaceITextBox:
IControl
{
voidSetText(stringtext);
}
interfaceIListBox:
IControl
{
voidSetItems(string[]items);
}
interfaceIComboBox:
ITextBox,IListBox{}
IComboBox的基接口是IControl、ItextBox和IListBox。
换言之,上面的IComboBox接口继承SetText、SetItems以及Paint。
如果一个类或结构实现某接口,则它还隐式实现该接口的所有基接口。
1.1.3接口体
接口的interface-body定义接口的成员。
interface-body:
{interface-member-declarationsopt}
1.2接口成员
接口的成员包括从基接口继承的成员和由接口本身声明的成员。
interface-member-declarations:
interface-member-declaration
interface-member-declarationsinterface-member-declaration
interface-member-declaration:
interface-method-declaration
interface-property-declaration
interface-event-declaration
interface-indexer-declaration
一个接口声明可以声明零个或多个成员。
接口的成员必须是方法、属性、事件或索引器。
接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型,也不能包含任何种类的静态成员。
所有接口成员都隐式地具有public访问属性。
接口成员声明中包含任何修饰符都属于编译时错误。
具体来说,不能使用修饰符abstract、public、protected、internal、private、virtual、override或static来声明接口成员。
在以下示例中:
publicdelegatevoidStringListEvent(IStringListsender);
publicinterfaceIStringList
{
voidAdd(strings);
intCount{get;}
eventStringListEventChanged;
stringthis[intindex]{get;set;}
}
声明了一个接口,该接口的成员涵盖了所有可能作为接口成员的种类:
方法、属性、事件和索引器。
interface-declaration创建新的声明空间(第3.3节),并且interface-declaration直接包含的interface-member-declarations将新成员提供给该声明空间。
以下规则适用于interface-member-declaration:
∙方法的名称必须与同一接口中声明的所有属性和事件的名称不同。
此外,方法的签名(第3.6节)必须不同于在同一接口中声明的所有其他方法的签名,并且在同一接口中声明的两种方法的签名不能只有ref和out不同。
∙属性或事件的名称必须与同一接口中声明的所有其他成员的名称不同。
∙一个索引器的签名必须区别于在同一接口中声明的其他所有索引器的签名。
准确地说,接口所继承的成员不是该接口的声明空间的一部分。
因此,允许接口用与它所继承的成员相同的名称或签名来声明新的成员。
发生这种情况时,则称派生的接口成员隐藏了基接口成员。
隐藏一个继承的成员不算是错误,但这确实会导致编译器发出警告。
为了避免出现上述警告,派生接口成员的声明中必须包含一个new修饰符,以指示该派生成员将要隐藏对应的基成员。
第3.7.1.2节中对该主题进行了进一步讨论。
如果在不隐藏所继承成员的声明中包含new修饰符,将对此状况发出警告。
通过移除new修饰符可取消显示此警告。
请注意,严格来讲,类object中的成员不是任何接口的成员(第13.2节)。
但是,通过在任何接口类型中进行成员查找,可获得类object中的成员(第7.3节)。
1.2.1接口方法
接口方法是使用interface-method-declaration来声明的:
interface-method-declaration:
attributesoptnewoptreturn-typeidentifier(formal-parameter-listopt);
接口方法声明中的attributes、return-type、identifier和formal-parameter-list与类中的方法声明的对应项(第10.5节)具有相同的意义。
不允许接口方法声明指定方法体,因此,声明总是以分号结尾。
1.2.2接口属性
接口属性是使用interface-property-declaration来声明的:
interface-property-declaration:
attributesoptnewopttypeidentifier{interface-accessors}
interface-accessors:
attributesoptget;
attributesoptset;
attributesoptget;attributesoptset;
attributesoptset;attributesoptget;
接口属性声明中的attributes、type和identifier与类中的属性声明的对应项(第10.6节)具有相同的意义。
接口属性声明的访问器与类属性声明(第10.6.2节)的访问器相对应,不同之处在于接口属性声明的访问器体必须始终是一个分号。
因此,访问器在这里只用于表示该属性为读写、只读还是只写。
1.2.3接口事件
接口事件是使用interface-event-declarations来声明的:
interface-event-declaration:
attributesoptnewopteventtypeidentifier;
接口事件声明中的attributes、type和identifier与类中事件声明的对应项(第10.7节)具有相同的意义。
1.2.4接口索引器
接口索引器是使用interface-indexer-declaration来声明的:
interface-indexer-declaration:
attributesoptnewopttypethis[formal-parameter-list]{interface-accessors}
接口索引器声明中的attributes、type和formal-parameter-list与类中索引器声明的对应项(第10.8节)具有相同的意义。
接口索引器声明的访问器与类索引器声明(第10.8节)的访问器相对应,不同之处在于接口索引器声明的访问器体必须始终是一个分号。
因此,访问器在这里只用于表示该索引器为读写、只读还是只写。
1.2.5接口成员访问
接口成员是通过I.M形式的成员访问(第7.5.4节)表达式和I[A]形式的索引器访问(第7.5.6.2节)表达式来访问的,其中I是接口类型,M是该接口类型的方法、属性或事件,A是索引器参数列表。
对于严格单一继承(继承链中的每个接口均恰巧有零个或一个直接基接口)的接口,成员查找(第
7.3节)、方法调用(第7.5.5.1节)和索引器访问(第7.5.6.2节)规则的效果与类和结构的完全相同:
派生程度较大的成员隐藏具有相同名称或签名的派生程度较小的成员。
然而,对于多重继承接口,当两个或更多个不相关(互不继承)的基接口中声明了具有相同名称或签名的成员时,就会发生多义性。
本节列出了此类情况的几个示例。
在所有情况下,都可以使用显式强制转换来解决这种多义性。
在下面的示例中
interfaceIList
{
intCount{get;set;}
}
interfaceICounter
{
voidCount(inti);
}
interfaceIListCounter:
IList,ICounter{}
classC
{
voidTest(IListCounterx){
x.Count
(1);//Error
x.Count=1;//Error
((IList)x).Count=1;//Ok,invokesIList.Count.set
((ICounter)x).Count
(1);//Ok,invokesICounter.Count
}
}
由于在IListCounter中对Count的成员查找(第7.3节)所获得的结果是不明确的,因此前两个语句将导致编译时错误。
如示例所阐释的,将x强制转换为适当的基接口类型就可以消除这种多义性。
此类强制转换没有运行时开销,它们只是在编译时将该实例视为派生程度较小的类型而已。
在下面的示例中
interfaceIInteger
{
voidAdd(inti);
}
interfaceIDouble
{
voidAdd(doubled);
}
interfaceINumber:
IInteger,IDouble{}
classC
{
voidTest(INumbern){
n.Add
(1);//InvokesIInteger.Add
n.Add(1.0);//OnlyIDouble.Addisapplicable
((IInteger)n).Add
(1);//OnlyIInteger.Addisacandidate
((IDouble)n).Add
(1);//OnlyIDouble.Addisacandidate
}
}
调用n.Add
(1)选择IInteger.Add,方法是应用7.4.2节的重载决策规则。
类似的,调用n.Add(1.0)选择IDouble.Add。
插入显式强制转换后,就只有一个候选方法了,因此没有多义性。
在下面的示例中
interfaceIBase
{
voidF(inti);
}
interfaceILeft:
IBase
{
newvoidF(inti);
}
interfaceIRight:
IBase
{
voidG();
}
interfaceIDerived:
ILeft,IRight{}
classA
{
voidTest(IDerivedd){
d.F
(1);//InvokesILeft.F
((IBase)d).F
(1);//InvokesIBase.F
((ILeft)d).F
(1);//InvokesILeft.F
((IRight)d).F
(1);//InvokesIBase.F
}
}
IBase.F成员被ILeft.F成员隐藏。
因此,即使在通过IRight的访问路径中IBase.F似乎没有被隐藏,调用d.F
(1)仍选择ILeft.F。
多重继承接口中的直观隐藏规则简单地说就是:
如果成员在任何一个访问路径中被隐藏,那么它在所有访问路径中都被隐藏。
由于从IDerived经ILeft到IBase的访问路径隐藏了IBase.F,因此该成员在从IDerived经IRight到IBase的访问路径中也被隐藏。
1.3完全限定接口成员名
接口成员有时也用它的完全限定名(fullyqualifiedname)来引用。
接口成员的完全限定名是这样组成的:
声明该成员的接口的名称,后跟一个点,再后跟该成员的名称。
成员的完全限定名将引用声明该成员的接口。
例如,给定下列声明
interfaceIControl
{
voidPaint();
}
interfaceITextBox:
IControl
{
voidSetText(stringtext);
}
Paint的完全限定名是IControl.Paint,SetText的完全限定名是ITextBox.SetText。
在上面的示例中,不能用ITextBox.Paint来引用Paint。
当接口是命名空间的组成部分时,该接口的成员的完全限定名需包含命名空间名称。
例如
namespaceSystem
{
publicinterfaceICloneable
{
objectClone();
}
}
这里,Clone方法的完全限定名是System.ICloneable.Clone。
1.4接口实现
接口可以由类和结构来实现。
为了指示类或结构实现了某接口,在该类或结构的基类列表中应该包含该接口的标识符。
例如:
interfaceICloneable
{
objectClone();
}
interfaceIComparable
{
intCompareTo(objectother);
}
classListEntry:
ICloneable,IComparable
{
publicobjectClone(){...}
publicintCompareTo(objectother){...}
}
如果一个类或结构实现某接口,则它还隐式实现该接口的所有基接口。
即使在类或结构的基类列表中没有显式列出所有基接口,也是这样。
例如:
interfaceIControl
{
voidPaint();
}
interfaceITextBox:
IControl
{
voidSetText(stringtext);
}
classTextBox:
ITextBox
{
publicvoidPaint(){...}
publicvoidSetText(stringtext){...}
}
在此,类TextBox同时实现了IControl和ITextBox。
1.4.1显式接口成员实现
为了实现接口,类或结构可以声明显式接口成员实现(explicitinterfacememberimplementation)。
显式接口成员实现就是一种方法、属性、事件或索引器声明,它使用完全限定接口成员名称作为标识符。
例如
interfaceICloneable
{
objectClone();
}
interfaceIComparable
{
intCompareTo(objectother);
}
classListEntry:
ICloneable,IComparable
{
objectICloneable.Clone(){...}
intIComparable.CompareTo(objectother){...}
}
在此,ICloneable.Clone和IComparable.CompareTo是显式接口成员实现。
某些情况下,接口成员的名称对于实现该接口的类可能是不适当的,此时,可以使用显式接口成员实现来实现该接口成员。
例如,一个实现“文件抽象”的类一般会实现一个具有释放文件资源作用的Close成员函数,同时还可能使用显式接口成员实现来实现IDisposable接口的Dispose方法:
interfaceIDisposable
{
voidDispose();
}
classMyFile:
IDisposable
{
voidIDisposable.Dispose(){
Close();
}
publicvoidClose(){
//Dowhat'snecessarytoclosethefile
System.GC.SuppressFinalize(this);
}
}
在方法调用、属性访问或索引器访问中,不能直接访问“显式接口成员实现”的成员,即使用它的完全限定名也不行。
“显式接口成员实现”的成员只能通过接口实例访问,并且在通过接口实例访问时,只能用该接口成员的简单名称来引用。
显式接口成员实现中包含访问修饰符属于编译时错误,而且如果包含abstract、virtual、override或static修饰符也属于编译时错误。
显式接口成员实现具有与其他成员不同的可访问性特征。
由于显式接口成员实现永远不能在方法调用或属性访问中通过它们的完全限定名来访问,因此,它们似乎是private(私有的)。
但是,因为它们可以通过接口实例来访问,所以它们似乎又是public(公共的)。
显式接口成员实现有两个主要用途:
∙由于显式接口成员实现不能通过类或结构实例来访问,因此它们就不属于类或结构的自身的公共接口。
当需在一个公用的类或结构中实现一些仅供内部使用(不允许外界访问)的接口时,这就特别有用。
∙显式接口成员实现可以消除因同时含有多个相同签名的接口成员所引起的多义性。
如果没有显式接口成员实现,一个类或结构就不可能为具有相同签名和返回类型的接口成员分别提供相应的实现,也不可能为具有相同签名和不同返回类型的所有接口成员中的任何一个提供实现。
为了使显式接口成员实现有效,声明它的类或结构必须在它的基类列表中指定一个接口,而该接口必须包含一个成员,该成员的完全限定名、类型和参数类型与该显式接口成员实现所具有的完全相同。
因此,在下列类中
classShape:
ICloneable
{
objectICloneable.Clone(){...}
intIComparable.CompareTo(objectother){...}//invalid
}
IComparable.CompareTo声明将导致编译时错误,原因是IComparable未列在Shape的基类列表中,并且不是ICloneable的基接口。
与此类似,在下列声明中
classShape:
ICloneable
{
objectICloneable.Clone(){...}
}
classEllipse:
Shape
{
objectICloneable.Clone(){...}//invalid
}
Ellipse中的ICloneable.Clone声明也将导致编译时错误,因为ICloneable未在Ellipse的基类列表中显式列出。
接口成员的完全限定名必须引用声明该成员的接口。
因此,下列声明中
interfaceIControl
{
voidPaint();
}
interfa
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 接口