原文:http://zhenyulu.cnblogs.com/archive/2006/04/18/377705.html

本文中所有图示纯为个人理解(参考了Assembly中元数据的存储方式),与真实情况可能有所出入。
图中绿色表示公有方法,红色表示私有方法。

本文将通过以下四个案例来分析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)中的某个公有或私有方法。上面代码在内存中的镜像可由下图描述:

从图中我们可以看到直接对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()”或者是静态、非公共的,或者有错误的返回类型。”

为什么会这样呢?如图:

这是由于接口规范中的方法默认的访问权限是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 EditBoxextends objectimplements IControl
{........method private hidebysig newslot virtual final instance void IControl.Paint() cil managed{.override IControl::Paint}
}

程序运行时内存中的镜像可简化表示为:

程序执行结果如下:

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!

程序执行时内存布局如下:

可见,EditBox中公有的Paint方法并不是接口实现方法,真正的接口实现方法是IControl.Paint,这将导致editbox.Paint()方法与((IControl)editbox).Paint()的执行结果并不一样。

5、结论

接口方法的实现通常是通过类中的公有方法实现的;

在一些特殊情况下(代码隐藏、一个类实现的两个接口具有相同的接口方法等),需要专门实现某个接口的方法。

转载于:https://www.cnblogs.com/dagon007/archive/2006/04/18/378307.html

C#中的接口 (转自吕振宇老师的blog)相关推荐

  1. C++中的接口(抽象类)

    1.Cpp中的接口(抽象类) 接口描述了类的行为和功能,而不需要完成类的特定实现.接口是使用抽象类来实现的,抽象类与数据抽象互不混淆,数据抽象是一个把实现细节与相关的数据分离开的概念.如果类中至少有一 ...

  2. Java中实现接口与继承的区别

    ** Java中实现接口与继承的区别 ** 首先,先来了解一下什么是接口和继承.接口一般是使用interface来定义的.接口定义同类的定义类似,分为接口的声明和接口体,其中接口体由常量定义和方法定义 ...

  3. Objective-C 入门(七)协议 protocol(JAVA中的接口)

    Objective-C 入门(七)协议 protocol(JAVA中的接口) 接口的作用想必大家都比较了解 OV中的 protocol 相比接口作用相似 语法稍有不同 1.先来看声明一个协议 在创建文 ...

  4. Android中Parcelable接口用法

    --  通过writeToParcel将你的对象映射成Parcel对象,再通过createFromParcel将Parcel对象映射成你的对象.也可以将Parcel看成是一个流,通过writeToPa ...

  5. Java中的接口命名[关闭]

    本文翻译自:Interface naming in Java [closed] Most OO languages prefix their interface names with a capita ...

  6. 初步解读Golang中的接口相关编写方法

    初步解读Golang中的接口相关编写方法 概述如果说goroutine和channel是Go并发的两大基石,那么接口是Go语言编程中数据类型的关键.在Go语言的实际编程中,几乎所有的数据结构都围绕接口 ...

  7. Java6.0中Comparable接口与Comparator接口详解

    Java6.0中Comparable接口与Comparator接口详解 说到现在,读者应该对Comparable接口有了大概的了解,但是为什么又要有一个Comparator接口呢?难道Java的开发者 ...

  8. C# 类中继承接口的属性

    在开发中面对接口编程,有时需要将属性放到接口中,但是在类中又要如何去继承接口的属性呢? 开始的时候,我以为只要继承了接口,就可以将属性拿来用了.代码如下: public interface IA {i ...

  9. java中接口什么时候用_我什么时候应该在java中使用接口?

    在Java中精确使用接口的一个很好的例子将是理想的,适用于任何特定的规则. 看看丹以前所有的问题,他似乎只是逐字逐句地张贴家庭作业/考试问题. 令人惊讶的是,这些不是考试题或其他-今天才找到这个网站, ...

最新文章

  1. hdu 2156 分数矩阵
  2. 中国厂商导致美国断网很稀奇?咱们早就被坑过了
  3. Serious Python
  4. 计算机社团发展目标,计算机社团工作计划
  5. 16进制颜色透明_PPT | 如何快速提取图片颜色之人生太卷
  6. Docker仓库搭建
  7. 封装JDBC事务操作,执行存储过程测试
  8. 程序员成长的10个阶段
  9. linux必备工具,Linux装机必备工具
  10. appinventor离线版下载_Chrome 离线安装包下载
  11. tika提取html,TIKA内容提取
  12. plt.fill()
  13. java子线程切换到主线程_Android子线程切换到UI线程方法总结
  14. Oracle study之--HASH Cluster特点
  15. 腾讯云服务器搭建小皮面板phpstudy教程
  16. DZ X页头主菜单背景图片透明自由更换页头背景图片的方法
  17. 网口扫盲三:以太网芯片MAC和PHY的关系
  18. python简单图片识别_用Python进行简单的图片识别(1)
  19. ubuntu搜狗输入法
  20. 洛谷P1080 [NOIP2012 提高组] 国王游戏(贪心,高精度)

热门文章

  1. android context继承关系,android中Context深入详解
  2. 20201014 《计算感知》第2节课 笔记
  3. JZOJ__Day 10:【普及模拟】【USACO】iCow播放器
  4. python最小公倍数 菜鸟_最小公倍数 golang + python
  5. mysql数据库连接6_c# – 实体框架的动态MySQL数据库连接6
  6. php 获取坐标api,怎么获取百度坐标api返回的json格式字符串或对象呢
  7. kettle对字符串去除空格_整理|ABAP基础知识二:常用字符串处理
  8. excel 进行二叉树_Excel下拉菜单,那些你不知道的操作
  9. BZOJ4432 : [Cerc2015]Greenhouse Growth
  10. 9.JAVA之GUI编程列出指定目录内容