代码改变世界

从IL代码来探讨C#中的接口方法、虚方法与抽象方法

2012-08-03 17:18 by Johnny Qian, 2244 阅读, 3 推荐, 收藏,

虚方法与抽象方法的比较是老生常谈的话题了。这次连带上接口方法来次深入探讨,从IL代码的层面来找出这些概念的不同之处。 首先贴上三种方法的C#与IL代码:

接口方法

C# Code:

interface ITest
{
    void Add(string s);
}

IL Code:

.class private interface abstract auto ansi ITest
{
    .method public hidebysig newslot abstract virtual instance void Add(string s) cil managed
    {
    }
}

虚方法

C# Code:

class Test
{
    public virtual void Add(string s)
    {
    }
}

IL Code:

.class private auto ansi beforefieldinit Test
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

    .method public hidebysig newslot virtual instance void Add(string s) cil managed
    {
    }
}

抽象方法

C# Code:

abstract class ATest
{
    public abstract void Add(string s);
}

IL Code:

.class private abstract auto ansi beforefieldinit ATest
    extends [mscorlib]System.Object
{
    .method family hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

    .method public hidebysig newslot abstract virtual instance void Add(string s) cil managed
    {
    }
}

三种方法的关键字对比

三种方法的声明中都有virtual关键字,这正体现了.Net中的三种多态:

  1. 接口多态
  2. 继承多态
  3. 抽象多态

除此之外,接口的方法还加上了abstract关键字,这表明了接口方法和抽象方法一样也不能声明函数体。 有了Virtual关键字,后代便可以通过override关键字来进行重写。于是我们来看看这三种方法重写后的方法在IL代码上有什么不同。

实现接口的类和方法

C# Code:

class A :ITest
{
    public void Add(string s)
    {
    }
}

IL Code:

.class private auto ansi beforefieldinit A
    extends [mscorlib]System.Object
    implements InterfaceTest.ITest
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

    .method public hidebysig newslot virtual final instance void Add(string s) cil managed
    {
    }
}

重写虚方法的类和方法

C# Code:

class B:Test
{
    public override void Add(string s)
    {
    }
}

IL Code:

.class private auto ansi beforefieldinit B
    extends InterfaceTest.Test
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

    .method public hidebysig virtual instance void Add(string s) cil managed
    {
    }
}

继承抽象方法的类和方法

C# Code:

class C:ATest
{
    public override void Add(string s)
    {
    }
}

IL Code:

.class private auto ansi beforefieldinit C
    extends InterfaceTest.ATest
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
    }

    .method public hidebysig virtual instance void Add(string s) cil managed
    {
    }
}

结论

  1. 接口方法隐式声明为 abstract virtual
  2. 抽象方法隐式声明为 virtual
  3. 接口的实现方法 被声明为 virtual final,且在重写时不需要添加关键字 override
  4. 对于CLR而言,虚方法与抽象方法是一样的
  5. 重写虚方法和抽象方法,均要添加关键字 override
  6. 由于实现接口的类的方法被标记为 virtual final,因此该类的后代不能再重写该接口方法了(即不需要再次实现祖先的接口)。
  7. 重写了虚方法和抽象方法的类的后代依然可以重写祖先的虚方法和抽象方法,因为重写后的方法仍被标记为 virtual。如果要阻止它的子孙类继续重写该虚方法或抽象方法,可在重写方法时加上关键字sealed,这样该重写方法被声明为 virtual final,和实现了接口的方法声明一样了,因此可以称接口方法为单层的虚方法。

有不对的地方,欢迎大家拍砖。

在ASP.NET Web Application中使用App_Code文件夹引发的异常

2012-05-19 23:24 by Johnny Qian, 7338 阅读, 11 推荐, 收藏,
摘要:在Visual Studio中,新建一个网站有两种方式:ASP.NET Web Site与ASP.NET Web Application。与Web Site相比,Web Application有很多优势。网上已经有很多文章来讲述它们的区别了,Visual Studio的官方博客有一篇文章讲述了它们各自的优劣点。 阅读全文

找回保存的路由器登录密码

2012-04-30 17:45 by Johnny Qian, 1126 阅读, 0 推荐, 收藏,
摘要:用路由器上网的朋友免不了经常登录路由器查看网络状态或配置信息,为了免去每次输入密码的麻烦,一般我们会选择记住密码。 这样一来,如果长久不手动输入密码,密码就会容易忘记。哪天重装了系统或者用什么优化工具清除了本地存储的密码,路由器就无法登陆了。虽然说可以重置路由器到出厂状态,但是路由器里面存储了ADSL密码、MAC地址绑定等等信息,重置到出厂状态后又得重新设置,也很麻烦。那有什么办法可以在系统保存了密码的情况下得到密码的明文呢? 阅读全文

Remove “Shared Folder Synchronization” from Right Click Context Menu

2011-07-25 10:15 by Johnny Qian, 1024 阅读, 0 推荐, 收藏,
摘要:Microsoft Office 2010 Professional and Professional Plus installs a handy option (Shared Folder Synchronization) to Desktop and Folder’s Context Menu for its Microsoft SharePoint Workspace formally known as “Groove”. 阅读全文

使用XSD文件验证XML文件

2011-07-22 16:18 by Johnny Qian, 6585 阅读, 0 推荐, 收藏,
摘要:相信大家对XML文件不会陌生。与XML文件在一起的通常还会有XSD文件。在我初步了解XML的时候就知道这个文件可以用来验证XML文件的schema,但是具体怎么个验证法,怎么用代码来对XML文件做校验,一直是模棱两可。刚好项目中用到了,于是就想写下来。 阅读全文

CSAPP 读书笔记:C语言中TMin的写法

2011-04-21 22:07 by Johnny Qian, 1533 阅读, 0 推荐, 收藏,
摘要:在CSAPP的图示和问题中,我们很小心的把32(TMin32)位有符号最小值写作-2147483647-1,为什么我们不直接写成-2147483648或0x80000000呢?不妨先打开limits.h头文件看看吧,你会发现它们也是用类似的诡异形式。 阅读全文

1033,2052 是什么意思?

2011-03-19 21:04 by Johnny Qian, 2785 阅读, 0 推荐, 收藏,
摘要:有时候我们去浏览软件安装后的目录,总会发现很多的安装目录下总有个名为 1033 或者 2052 目录。后来才明白,这个叫 LCID(Locale ID,区域性标识符)。 阅读全文

Web Deployment Project

2010-12-30 15:25 by Johnny Qian, 911 阅读, 1 推荐, 收藏,
摘要:新接手一个项目,发现解决方案中有些Project不能打开,如下所示。在项目上点击右键,选择编辑项目文件。可以看到,项目文件的扩展名为wdproj,打开这个XML文件后,可以看到这是一个Web Deployment Project。按照注释中的链接,可以找到这个项目模板的下载地址:http://www.microsoft.com/downloads/en/details.aspx?FamilyId=0AA30AE8-C73B-4BDD-BB1B-FE697256C459&displaylang=en在下载页面,可以看到关于这种项目类型的介绍。 阅读全文

WCF最佳实践之 Dispose Proxy

2010-12-25 17:12 by Johnny Qian, 391 阅读, 0 推荐, 收藏,
摘要:// Not Recommendusing (IMyContract proxy = new MyContractClient( )){ proxy.MyMethod();} // this line might throw a CommunicationObjectFaultedException// RecommendIMyContract proxy = new MyContractClient();try{ proxy.MyMethod(); proxy.Close();}catch{ proxy.Abort();}另附一篇dudu的文章:http://www.... 阅读全文

VS安装目录中的C#语言规范

2010-11-30 14:40 by Johnny Qian, 667 阅读, 0 推荐, 收藏,
摘要:VS安装占用的磁盘空间可真大,不过这么大的容量中还隐藏着不少好东西,在VS的安装目录中就有C#的语言规范。 VS2008的安装路径:C:\Program Files\Microsoft Visual Studio 9.0\VC#\Specifications\1033,这里包含的是C# 3.0版的语言规范。 VS2010的安装路径:C:\Program Files\Microsoft Visual Studio 10.0\VC#\Specifications\1033,这里包含的是C# 4.0版的语言规范。 C#的1.2和2.0的语言规范在VS2005的安装目录中,估计现在大家也不怎么用VS2005了吧。 阅读全文
点击右上角即可分享
微信分享提示