C#中的接口(转)

转自:http://www.cnblogs.com/zhenyulu/articles/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 EditBox
      extends object
      implements 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、结论

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

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

C#中的接口的更多相关文章

  1. 通过拦截器Interceptor实现Spring MVC中Controller接口访问信息的记录

    java web工程项目使用了Spring+Spring MVC+Hibernate的结构,在Controller中的方法都是用于处理前端的访问信息,Controller通过调用Service进行业务 ...

  2. 【总结】浅谈JavaScript中的接口

    一.什么是接口 接口是面向对象JavaScript程序员的工具箱中最有用的工具之一.在设计模式中提出的可重用的面向对象设计的原则之一就是“针对接口编程而不是实现编程”,即我们所说的面向接口编程,这个概 ...

  3. 介绍Unreal Engine 4中的接口(Interface)使用C++和蓝图

    这个教程是从UE4 Wiki上整理而来. 在C++中直接使用Interface大家应该很熟悉.只是简单先定义一个个有虚函数的基类,然后在子类中实现相应的虚函数.像这样的虚函数的基类一般概念上叫接口.那 ...

  4. Myeclipse中打开接口实现类的快捷键

    Myeclipse中打开接口实现类的快捷键-----Ctrl + T Myeclipse中 Open Type快捷键-----Ctrl + Shift + T

  5. 在网页程序或Java程序中调用接口实现短信猫收发短信的解决方案

    方案特点: 在网页程序或Java程序中调用接口实现短信猫收发短信的解决方案,简化软件开发流程,减少各应用系统相同模块的重复开发工作,提高系统稳定性和可靠性. 基于HTTP协议的开发接口 使用特点在网页 ...

  6. Android中的接口回调技术

    Android中的接口回调技术有很多应用的场景,最常见的:Activity(人机交互的端口)的UI界面中定义了Button,点击该Button时,执行某个逻辑. 下面参见上述执行的模型,讲述James ...

  7. Spring中Ordered接口简介

    目录 前言 Ordered接口介绍 Ordered接口在Spring中的使用 总结 前言 Spring中提供了一个Ordered接口.Ordered接口,顾名思义,就是用来排序的. Spring是一个 ...

  8. 面向对象编程语言中的接口(Interface)

    在大多面向对象的编程语言中都提供了Interface(接口)的概念.如果你事先学过这个概念,那么在谈到“接口测试”时,会不会想起这个概念来!?本篇文章简单介绍一下面向对象编程语言中的Interface ...

  9. Java和C#中的接口对比(有你不知道的东西)

    1.与Java不同,C#中的接口不能包含字段(Field). 在java中,接口中可以包含字段,但是这些字段隐式地是static和final的.而C#不允许接口中有字段,编译器在编译时就会提示错误(如 ...

随机推荐

  1. log4j设置日志格式为UTF-8

    想要log4j输出的日志文件的编码格式为UTF-8.正常情况下只需要添加下述的代码即可: log4j.appender.appender_name.Encoding=UTF-8 但是在spring与l ...

  2. JqueryEasyUI 解决IE下datagrid无法刷新的问题 分类: JavaScript JqueryEasyUI 2014-09-20 10:05 510人阅读 评论(1) 收藏

    问题描述: 在使用JqueryEasyUI 时,发现在IE下$('#table').datagrid('reload');无效,数据并没有被刷新,究其原因,是因为刷新时,datagrid请求的url没 ...

  3. hdu 4050 2011北京赛区网络赛K 概率dp ***

    题目:给出1-n连续的方格,从0开始,每一个格子有4个状态,左右脚交替,向右跳,而且每一步的步长必须在给定的区间之内.当跳出n个格子或者没有格子可以跳的时候就结束了,求出游戏的期望步数 0:表示不能到 ...

  4. [Linux] yum和apt-get用法及区别

    一般来说著名的linux系统基本上分两大类: 1.RedHat系列:Redhat.Centos.Fedora等 2.Debian系列:Debian.Ubuntu等 RedHat 系列 1 常见的安装包 ...

  5. Oracle中“行转列”的实现方式

    在报表的开发当中,难免会遇到行转列的问题. 以Oracle中scott的emp为例,统计各职位的人员在各部门的人数分布情况,就可以用“行转列”: scott的emp的原始数据为: EMPNO ENAM ...

  6. 通讯录(ios自带无界面)

    1,添加框架AddressBook.framework 2,请求权限认证,在Appdelegate.m文件中 - (BOOL)application:(UIApplication *)applicat ...

  7. ps命令使用 进程查看

    ps命令是Process Status的缩写 用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信息,就可以使用top命 ...

  8. C#经典机试题(猫叫)

    猫大叫一声,所有的老鼠都开始逃跑,主人被惊醒.(C#语言) 1.要有联动性,老鼠和主人的行为是被动的. 2.考虑可扩展性,猫的叫声可能引起其他联动效应. public interface Observ ...

  9. js String对象

    字符串(String) 字符串(String)使用长度属性length来计算字符串的长度: 在字符串中查找字符串 字符串使用 indexOf() 来定位字符串中某一个指定的字符首次出现的位置: 实例 ...

  10. MatLab有关路径的几个命令

    窗外雨如注,国庆的第3天,没钱出去逛,更新我的博客吧 今天要说的命令有path.cd.userpath.savepath.pathtool 有两种改变启动目录的方法,第1种使用userpath和sav ...