C#.NET隐式和显式接口方法实现幕后发生的故事

原创 2017年06月09日 10:16:45

在C#中,一个类型加载到CLR中,会为该类型创建并初始化一个方法表(读者可自行搜索 CLR的执行模型)。在这个方法表中,类型引入的每个新方法都有一条对应的纪录项。以及该类型继承的所有虚方法添加了记录项。继承的虚方法既有父类定义的方法,也有接口定义。例如:

 interface IParent
    {
        void Test();
    }
    class Children : IParent
    {
        public void Test()
        {
            Console.WriteLine("Children Method");
        }
    }

那么方法表中将包含与以下方法对应的纪录项:
Object(隐式继承的基类)定义的所有虚实例方法。
IParent(继承接口的方法Test)
Children中的新方法Test

(关于内存中的方法,可参考这篇文章:http://blog.csdn.net/u010533180/article/details/52709684)
为了简化编程,C# 编译器假定Children 引入的Test 方法是对IParent的Test的方法的实现。C#编译器之所以这样做出假定,是因为Test方法的可访问性是public,而且接口方法的签名和新引入的方法完全一致。也就是说两个方法具有相同的参数和返回类型。如果新的Test方法被标记为virtual,C#编译器仍会认为该方法匹配与接口方法。

C#编译器将一个新的方法和一个接口方法匹配起来之后,会生成元数据,指明Children类型方法表中的两个纪录项应引用同一个实现。为了更清楚的理解这一点,下面用代码演示调用Test方法:

public static void Main()
        {
            Children children = new Children();
            children.Test();
            IParent par = children;
            par.Test();
        }

在第一个Test方法调用中,Children定义的Test方法被调用。然后定义一个IParent接口类型的变量par,对应的引用为Children对象。然后再调用Test方法时,是调用的IParent接口的Test方法。由于C#要求公共的Test方法还必须是IParent的Test方法的实现,所以会执行相同的代码,输出相同的结果。
输出的结果都为:

 Children Method
Children Method

现在修改一下接口方法的实现:再来看一下结果

  interface IParent
    {
        void Test();
    }
    class Children : IParent
    {
        public void Test()
        {
            Console.WriteLine("Children Method");
        }
         void IParent.Test()
        {
            Console.WriteLine("IParent Method");
        }
    }
        public static void Main()
        {
            Children children = new Children();
            children.Test();
            IParent par = children;
            par.Test();
        }

输出的结果为:

Children Method
IParent Method

在C#中将定义方法的那个接口的名称作为方法名的前缀,例如上面的IParent.Test,创建的就是一个显式接口方法实现(Explicit Interface Method Implementation ,EIMI)。注意,在C#中定义一个显式接口方法时,不允许指定可访问性(public或者private等)。否则编译器汇报错误,例如下图这里写图片描述

但是编译器生成方法的元数据时,其可访问性会被自动设为private,防止其它代码在使用类的实例时直接调用接口方法。要调用接口方法,只能通过接口类型的一个变量来进行。还要注意,一个EIMI方法不能标记为virtual,所以它不能被重写。这是因为EIMI方法并非真的是类型对象模型的一部分,它是将一个接口(一组行为或者方法)连接到一个类型上,同时避免公开行为/方法的一种方式。这也同样解释了把鼠标放在接口上时为什么会有两种方法的实现。
这里写图片描述

当然出现上述图片时 也有可能多个接口具有相同的方法名称,这时必须显式实现了。

参考来源:CLR VIA C# 第三版 第13章 13.5节。

版权声明:本文为博主原创文章,未经博主允许不得转载。

.NET中的三种接口实现方式

一般来说.NET提供了三种不同的接口实现方式,分别为隐式接口实现、显式接口实现、混合式接口实现。这三种方式各有各的特点。 首先来看隐式接口实现,这恐怕是我们使用最多的一种接口实现,因为隐匿接口实现是...
  • lee880926
  • lee880926
  • 2014年10月30日 14:30
  • 338

32位和64位编程注意事项总结

http://www.oschina.net/p/flowvisor   http://www.cnblogs.com/centimeter/articles/2395405.html ...
  • baidu_36226689
  • baidu_36226689
  • 2016年11月02日 11:45
  • 2265

Fortran77-90-95

Fortran语言的历史 Fortran是英文FORmula TRANslation的缩写, 意为"公式翻译". 为科学, 工程问题中那些能够用数学公式表达的问题而设计的语言, 主要用于数值计算. ...
  • nancygreen
  • nancygreen
  • 2013年04月26日 19:06
  • 3973

接口的显式实现与隐式实现

我们在实现接口时,常常是类继承接口,然后在接口中实现相应的方法。代码如下: interface IOutput { void output(); } cl...
  • xxdddail
  • xxdddail
  • 2014年09月16日 08:33
  • 1974

C#中接口的显式和隐式实现

接口的实现分为:隐式实现和显式实现。如果类或者结构要实现的是单个接口,可以使用隐式实现,如果类或者结构继承了多个接口那么接口中相同名称成员就要显式实现。显示实现是通过使用接口的完全限定名来实现接口成员...
  • NETZHOU
  • NETZHOU
  • 2008年01月22日 11:14
  • 2926

APR分析-整体篇 http://blog.csdn.net/jmshl/article/details/6773731

APR分析-整体篇 由于部门所使用的底层库与Apache Server有着“一定的渊源”,所以总有一种想看看Apache的实现的冲动。最近项目收尾,愿望终可实现。   一、何为APR...
  • wangyin159
  • wangyin159
  • 2015年09月07日 21:15
  • 1405

4GL错误代码编号

-12没有足够的核心。                                                                                 作业系统错...
  • mars_jin
  • mars_jin
  • 2013年10月16日 10:54
  • 5163

接口的显示实现和隐式实现一点笔记

隐式实现 不知道成员的归属 显示实现 显示指定成员的归属(通过 接口名.成员 )显式实现避免了成员归属混淆不清的情况,特别是多个接口中有相同的成员,或者接口中成员和类自己的成员冲突的情况。隐式实现...
  • shanghongshen
  • shanghongshen
  • 2015年07月30日 10:42
  • 1182

C# 隐式接口和显示接口的区别

先看个例子 声明两个接口 public interface IFg { int Add(); void Fei(); } pub...
  • w200221626
  • w200221626
  • 2016年07月26日 10:34
  • 1403

JVM 学习笔记

JVM学习笔记-方法区(Method Area)  方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码...
  • qilixiang012
  • qilixiang012
  • 2015年03月23日 17:12
  • 1037
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#.NET隐式和显式接口方法实现幕后发生的故事
举报原因:
原因补充:

(最多只允许输入30个字)