C#中的接口
2014-05-06 21:12
357 查看
本文中所有图示纯为个人理解(参考了Assembly中元数据的存储方式),与真实情况可能有所出入。 图中绿色表示公有方法,红色表示私有方法。
本文将通过以下四个案例来分析C#中的接口究竟是如何工作的。
实现接口的类需要实现所有接口方法。通常情况下,接口的实现方法也为public型。如下案例:
程序的执行结果为:
接口就好像是关系型数据库中的一对多表,一个接口对应多个接口方法,每个接口方法又对应虚拟方法表(VMT)中的某个公有或私有方法。上面代码在内存中的镜像可由下图描述:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic034.gif)
从图中我们可以看到直接对Paint方法的调用以及通过接口对Paint方法的调用。可见通过接口对方法进行调用需要多出一道转换工作,因此执行效率不如直接调用。
程序在编译时将显示如下编译错误:““EditBox”不会实现接口成员“IControl.Paint()”。“EditBox.Paint()”或者是静态、非公共的,或者有错误的返回类型。”
为什么会这样呢?如图:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic035.gif)
这是由于接口规范中的方法默认的访问权限是public,而类中的默认访问权限是default,也就是说private,因此导致权限范围收缩,两者权限并不相同,所以必须将类的权限调整为public才可以使上面的代码得以执行。
EditBox类拥有一私有Paint方法,但这并不是接口方法的实现(上例已经分析过)。EditBox类中还包含了一“void IControl.Paint()”方法, 是该方法复写了接口的Paint方法,该方法是私有的(通过IL代码可以看出)。
注意:“void IControl.Paint()”前不能加任何的修饰限定符号,诸如public、private等,这在C#的语法中是不允许的。该方法反编译得到的IL代码如下:
程序运行时内存中的镜像可简化表示为:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic036.gif)
程序执行结果如下:
我们之所以可以通过
程序执行结果如下:
程序执行时内存布局如下:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic037.gif)
可见,EditBox中公有的Paint方法并不是接口实现方法,真正的接口实现方法是IControl.Paint,这将导致
在一些特殊情况下(代码隐藏、一个类实现的两个接口具有相同的接口方法等),需要专门实现某个接口的方法。
【版权声明】转载请注明出处:http://zhenyulu.cnblogs.com/archive/2006/04/18/377705.html
本文将通过以下四个案例来分析C#中的接口究竟是如何工作的。
1、公有方法实现接口方法
尽管C#在定义接口时不用指明接口方法的访问控制方式,但默认接口方法均为public型(这可以从反编译的IL代码中看到)。下面是使用Reflector查看的接口IL代码.class private interface abstract auto ansi IControl { .method public hidebysig newslot abstract virtual instance void Paint() cil managed { } }
实现接口的类需要实现所有接口方法。通常情况下,接口的实现方法也为public型。如下案例:
using System ; interface IControl { void Paint(); } public class EditBox: IControl { public void Paint() { Console.WriteLine("Pain method is called!"); } } class Test { static void Main() { EditBox editbox = new EditBox(); editbox.Paint(); ((IControl)editbox).Paint(); } }
程序的执行结果为:
Pain method is called! Pain method is called!
接口就好像是关系型数据库中的一对多表,一个接口对应多个接口方法,每个接口方法又对应虚拟方法表(VMT)中的某个公有或私有方法。上面代码在内存中的镜像可由下图描述:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic034.gif)
从图中我们可以看到直接对Paint方法的调用以及通过接口对Paint方法的调用。可见通过接口对方法进行调用需要多出一道转换工作,因此执行效率不如直接调用。
2、私有方法不能实现接口方法
如果想将接口方法直接实现为私有方法是办不到的。下面的EditBox的代码中Paint方法没有特殊说明,默认为private,导致代码无法执行:using System ; interface IControl { void Paint(); } public class EditBox: IControl { void Paint() { Console.WriteLine("Pain method is called!"); } public void ShowPaint() { this.Paint(); ((IControl)this).Paint(); } } class Test { static void Main() { EditBox editbox = new EditBox(); editbox.ShowPaint(); } }
程序在编译时将显示如下编译错误:““EditBox”不会实现接口成员“IControl.Paint()”。“EditBox.Paint()”或者是静态、非公共的,或者有错误的返回类型。”
为什么会这样呢?如图:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic035.gif)
这是由于接口规范中的方法默认的访问权限是public,而类中的默认访问权限是default,也就是说private,因此导致权限范围收缩,两者权限并不相同,所以必须将类的权限调整为public才可以使上面的代码得以执行。
3、实现专门的接口方法(1)
代码如下:using System ; interface IControl { void Paint(); } public class EditBox: IControl { void Paint() { Console.WriteLine("Pain method is called!"); } void IControl.Paint() { Console.WriteLine("IControl.Pain method is called!"); } public void ShowPaint() { this.Paint(); ((IControl)this).Paint(); } } class Test { static void Main() { EditBox editbox = new EditBox(); editbox.ShowPaint(); //editbox.Paint(); ((IControl)editbox).Paint(); } }
EditBox类拥有一私有Paint方法,但这并不是接口方法的实现(上例已经分析过)。EditBox类中还包含了一“void IControl.Paint()”方法, 是该方法复写了接口的Paint方法,该方法是私有的(通过IL代码可以看出)。
注意:“void IControl.Paint()”前不能加任何的修饰限定符号,诸如public、private等,这在C#的语法中是不允许的。该方法反编译得到的IL代码如下:
.class public auto ansi beforefieldinit EditBox extends object implements IControl { ....... .method private hidebysig newslot virtual final instance void IControl.Paint() cil managed { .override IControl::Paint } }
程序运行时内存中的镜像可简化表示为:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic036.gif)
程序执行结果如下:
Pain method is called! IControl.Pain method is called! IControl.Pain method is called!
我们之所以可以通过
((IControl)editbox).Paint()方法访问到代码是因为接口方法Paint是公有的。但是我们不能通过
editbox.Paint()方法访问到代码是因为EditBox的Paint方法是私有的。 在EditBox内部,通过ShowPaint方法可以同时访问私有的Paint方法与接口
IControl.Paint方法。
4、实现专门的接口方法(2)
如果EditBox中的Pait方法为公有并且同时提供了IControl.Paint方法,程序将是如何运行的呢?代码如下:using System ; interface IControl { void Paint(); } public class EditBox: IControl { public void Paint() { Console.WriteLine("Pain method is called!"); } void IControl.Paint() { Console.WriteLine("IControl.Pain method is called!"); } } class Test { static void Main() { EditBox editbox = new EditBox(); editbox.Paint(); ((IControl)editbox).Paint(); } }
程序执行结果如下:
Pain method is called! IControl.Pain method is called!
程序执行时内存布局如下:
![](http://images.cnblogs.com/cnblogs_com/zhenyulu/200508/Pic037.gif)
可见,EditBox中公有的Paint方法并不是接口实现方法,真正的接口实现方法是IControl.Paint,这将导致
editbox.Paint()方法与
((IControl)editbox).Paint()的执行结果并不一样。
5、结论
接口方法的实现通常是通过类中的公有方法实现的;在一些特殊情况下(代码隐藏、一个类实现的两个接口具有相同的接口方法等),需要专门实现某个接口的方法。
【版权声明】转载请注明出处:http://zhenyulu.cnblogs.com/archive/2006/04/18/377705.html
相关文章推荐
- 小菜的ArcObjects学习之路------C#中接口的转换
- C#.net 微信公众账号接口开发
- C#接口实例详解
- c#接口应用
- C#接口-接口作用
- C#开发中三层架构BLL,DAL还有IBLL和IDAL接口,请问为什么要定义接口?有什么用啊?
- C#导出到Excel——无法嵌入互操作类型“Microsoft.Office.Interop.Excel.ApplicationClass”。请改用适用的接口。
- CLR via C# 13.11 设计:基类还是接口
- Head First C# 中文版 图文皆译 第七章 接口和抽象类 page272
- C#之类继承,接口学习案例
- Head First C# 中文版 图文皆译 第七章 接口和抽象类 page273
- C# 入门(11) 接口(interface)
- [转]C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解
- C#中的抽象类和接口
- Head First C# 中文版 图文皆译 第七章 接口和抽象类 page282
- C#进阶系列——WebApi 接口参数不再困惑:传参详解
- C#调用VC的DLL的接口函数参数类型转换一览表
- C#条形码生成(一)----接口、Code128基础数据、枚举
- 一个C#编写QQ接口软件--QQ协议(转)
- 黑马程序员_C#接口的定义与使用