C# base和this[转]

By | 09月10日
Advertisement

new关键字引起了大家的不少关注,尤其感谢Anders Liu的补充,让我感觉博客园赋予的交流平台真的无所不在。所以,我们就有必要继续这个话题,把我认为最值得关注的关键字开展下去,本文的重点是访问关键字(Access Keywords):base和this。虽然访问关键字不是很难理解的话题,我们还是有可以深入讨论的地方来理清思路。还是老办法,我的问题先列出来,您是否做好了准备。

  • 是否可以在静态方法中使用base和this,为什么?

  • base常用于哪些方面?this常用于哪些方面?

  • 可以base访问基类的一切成员吗?

  • 如果有三层或者更多继承,那么最下级派生类的base指向那一层呢?例如.NET体系中,如果以base访问,则应该是直接父类实例呢,还是最高层类实例呢?

  • 以base和this应用于构造函数时,继承类对象实例化的执行顺序如何?

  2. 基本概念

  base和this在C#中被归于访问关键字,顾名思义,就是用于实现继承机制的访问操作,来满足对对象成员的访问,从而为多态机制提供更加灵活的处理方式。

  2.1 base关键字

  其用于在派生类中实现对基类公有或者受保护成员的访问,但是只局限在构造函数、实例方法和实例属性访问器中,MSDN中小结的具体功能包括:

  • 调用基类上已被其他方法重写的方法。

  • 指定创建派生类实例时应调用的基类构造函数。

  2.2 this关键字

  其用于引用类的当前实例,也包括继承而来的方法,通常可以隐藏this,MSDN中的小结功能主要包括:

  • 限定被相似的名称隐藏的成员

  • 将对象作为参数传递到其他方法

  • 声明索引器

  3. 深入浅出

  3.1 示例为上

  下面以一个小示例来综合的说明,base和this在访问操作中的应用,从而对其有个概要了解,更详细的规则和深入我们接着阐述。本示例没有完全的设计概念,主要用来阐述base和this关键字的使用要点和难点阐述,具体的如下:

C# base和this[转]
C# base和this[转]

base和this示例using System;namespace Anytao.net.My_Must_net{publicclass Action{publicstaticvoid ToRun(Vehicle vehicle){Console.WriteLine("{0} is running.", vehicle.ToString());}}publicclass Vehicle{privatestring name;privateint speed;privatestring[] array =newstring[10];

public Vehicle(){}//限定被相似的名称隐藏的成员public Vehicle(string name, int speed){this.name = name;this.speed = speed;}publicvirtualvoid ShowResult(){Console.WriteLine("The top speed of {0} is {1}.", name, speed);}publicvoid Run(){//传递当前实例参数            Action.ToRun(this);}//声明索引器,必须为this,这样就可以像数组一样来索引对象publicstringthis[int param]{get{return array[param];}set{array[param] = value;}}}publicclass Car: Vehicle{//派生类和基类通信,以base实现,基类首先被调用//指定创建派生类实例时应调用的基类构造函数public Car(): base("Car", 200){ }

public Car(string name, int speed): this(){ }

publicoverridevoid ShowResult(){//调用基类上已被其他方法重写的方法base.ShowResult();Console.WriteLine("It's a car's result.");}}publicclass Audi : Car{public Audi(): base("Audi", 300){ }

public Audi(string name, int speed): this(){ }publicoverridevoid ShowResult(){//由三层继承可以看出,base只能继承其直接基类成员base.ShowResult();base.Run();Console.WriteLine("It's audi's result.");}}publicclass BaseThisTester{publicstaticvoid Main(string[] args){Audi audi =new Audi();audi[1] ="A6";audi[2] ="A8";Console.WriteLine(audi[1]);audi.Run();audi.ShowResult();}}}

  3.2 示例说明

  上面的示例基本包括了base和this使用的所有基本功能演示,具体的说明可以从注释中得到解释,下面的说明是对注释的进一步阐述和补充,来说明在应用方面的几个要点:

  • base常用于,在派生类对象初始化时和基类进行通信。

  • base可以访问基类的公有成员和受保护成员,私有成员是不可访问的。

  • this指代类对象本身,用于访问本类的所有常量、字段、属性和方法成员,而且不管访问元素是任何访问级别。因为,this仅仅局限于对象内部,对象外部是无法看到的,这就是this的基本思想。另外,静态成员不是对象的一部分,因此不能在静态方法中引用this。

  • 在多层继承中,base可以指向的父类的方法有两种情况:一是有重载存在的情况下,base将指向直接继承的父类成员的方法,例如Audi类中的ShowResult方法中,使用base访问的将是Car.ShowResult()方法,而不能访问Vehicle.ShowResult()方法;而是没有重载存在的情况下,base可以指向任何上级父类的公有或者受保护方法,例如Audi类中,可以使用base访问基类Vehicle.Run()方法。这些我们可以使用ILDasm.exe,从IL代码中得到答案。

C# base和this[转]
C# base和this[转]

Code.method public hidebysig virtual instance void ShowResult() cil managed{// 代码大小       27 (0x1b)  .maxstack  8IL_0000:  nopIL_0001:  ldarg.0//base调用父类成员  IL_0002:  call       instance void Anytao.net.My_Must_net.Car::ShowResult()IL_0007:  nopIL_0008:  ldarg.0//base调用父类成员,因为没有实现Car.Run(),所以指向更高级父类  IL_0009:  call       instance void Anytao.net.My_Must_net.Vehicle::Run()IL_000e:  nopIL_000f:  ldstr      "It's audi's result."IL_0014:  call       void [mscorlib]System.Console::WriteLine(string)IL_0019:  nopIL_001a:  ret} // end of method Audi::ShowResult

  3.3 深入剖析

  如果有三次或者更多继承,那么最下级派生类的base指向那一层呢?例如.NET体系中,如果以base访问,则应该是直接父类实例呢,还是最高层类实例呢?

  首先我们有必要了解类创建过程中的实例化顺序,才能进一步了解base机制的详细执行过程。一般来说,实例化过程首先要先实例化其基类,并且依此类推,一直到实例化System.Object为止。因此,类实例化,总是从调用System.Object.Object()开始。因此示例中的类Audi的实例化过程大概可以小结为以下顺序执行,详细可以参考示例代码分析。

  • 执行System.Object.Object();

  • 执行Vehicle.Vehicle(string name, int speed);

  • 执行Car.Car();

  • 执行Car.Car(string name, int speed);

  • 执行Audi.Audi();

  • 执行Audi.Audi(string name, int speed)。

  我们在充分了解其实例化顺序的基础上就可以顺利的把握base和this在作用于构造函数时的执行情况,并进一步了解其基本功能细节。

  下面更重要的分析则是,以ILDASM.exe工具为基础来分析IL反编译代码,以便更深层次的了解执行在base和this背后的应用实质,只有这样我们才能说对技术有了基本的剖析。

Main方法的执行情况为:

C# base和this[转]
C# base和this[转]

IL分析base和this执行.method public hidebysig staticvoid  Main(string[] args) cil managed{.entrypoint// 代码大小       61 (0x3d)  .maxstack  3.locals init (class Anytao.net.My_Must_net.Audi V_0)IL_0000:  nop//使用newobj指令创建新的对象,并调用构造函数初始化  IL_0001:  newobj     instance void Anytao.net.My_Must_net.Audi::.ctor()IL_0006:  stloc.0IL_0007:  ldloc.0IL_0008:  ldc.i4.1IL_0009:  ldstr      "A6"IL_000e:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::set_Item(int32,string)IL_0013:  nopIL_0014:  ldloc.0IL_0015:  ldc.i4.2IL_0016:  ldstr      "A8"IL_001b:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::set_Item(int32,string)IL_0020:  nopIL_0021:  ldloc.0IL_0022:  ldc.i4.1IL_0023:  callvirt   instance string Anytao.net.My_Must_net.Vehicle::get_Item(int32)IL_0028:  call       void [mscorlib]System.Console::WriteLine(string)IL_002d:  nopIL_002e:  ldloc.0IL_002f:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::Run()IL_0034:  nopIL_0035:  ldloc.0//base.ShowResult最终调用的是最高级父类Vehicle的方法,//而不是直接父类Car.ShowResult()方法,这是应该关注的  IL_0036:  callvirt   instance void Anytao.net.My_Must_net.Vehicle::ShowResult()IL_003b:  nopIL_003c:  ret} // end of method BaseThisTester::Main

因此,对重写父类方法,最终指向了最高级父类的方法成员。

  4. 通用规则

  • 尽量少用或者不用base和this。除了决议子类的名称冲突和在一个构造函数中调用其他的构造函数之外,base和this的使用容易引起不必要的结果。

  • 在静态成员中使用base和this都是不允许的。原因是,base和this访问的都是类的实例,也就是对象,而静态成员只能由类来访问,不能由对象来访问。

  • base是为了实现多态而设计的。

  • 使用this或base关键字只能指定一个构造函数,也就是说不可同时将this和base作用在一个构造函数上。

  • 简单的来说,base用于在派生类中访问重写的基类成员;而this用于访问本类的成员,当然也包括继承而来公有和保护成员。

  • 除了base,访问基类成员的另外一种方式是:显示的类型转换来实现。只是该方法不能为静态方法。

http://www.cnblogs.com/reommmm/archive/2009/03/23/1419573.html

Similar Posts:

  • SharePoint Claim base authentication EnsureUser 不带claim(i:0#.w|)user Failed

    环境信息: 带有Form base authentication(FBA).Active Directory Federation Services(ADFS).以及windows Authentication的混合认证的SharePoint环境. 问题具体描述: 在该环境中,调用EnsureUser添加一个普通的AD user,sharepoint 会throw "The specified user userLoginName could not be found.",当然此处的u

  • Snort + base 入侵检测配置

    snort的配置分为5个部分 一 snort 简单介绍 snort入侵检测的使用方法和处理工程 本文基于rhel5.4 libpcap-0.9.4-8.1 snort-2.8.0 首先需要下载mysql apache php libpcap adodb snort base等软件 libpcap 是linux/unix 平台下捕获数据包的函数库 mysql是数据库,存放捕获的数据 apache是web服务器 php 网页脚本语言 adobd 为php提供数据库支持 (adobd is datab

  • 【Java EE 学习 69 下】【数据采集系统第一天】【实体类分析和Base类书写】

    之前SSH框架已经搭建完毕,现在进行实体类的分析和Base类的书写.Base类是抽象类,专门用于继承. 一.实体类关系分析 既然是数据采集系统,首先调查实体(Survey)是一定要有的,一个调查有多个页面(Page),一个页面有多个问题(Question),所以还要有页面和问题实体.参与完成调查之后一定还会生成若干个答案,所以还有答案实体(Answer),当然还有参与的用户(User),管理员是特殊的User,只需要登陆的时候进行判断即可. 分析实体类型是比较简单的,最重要的是设计,怎样设计才能

  • SMACSS:一个关于CSS的最佳实践-2.Base Rules

    回顾 在上一篇SMACSS:一个关于CSS的最佳实践-Overview中,讲到SMACSS将CSS Rules分为5个Categories: Base Layout Module State Theme 本篇我们将介绍Base Rules.你可以将所有Base Rules放在一个文件,比如 base.css :当然,也可以不这么做.区分Category的作用是帮助我们区分出不同功能的CSS,提高可重用性,可维护性. 哪些CSS属于Base Rules? Base Rules指的是所有元素的默认s

  • Data Base MongoDB常用命令

    Data Base MongoDB常用命令 一.常用查询命令: 1 Query.All("name", new List<BsonValue> { BsonValue.Create("a"), BsonValue.Create("b") });//通过多个元素来匹配数组 2 Query.And(Query.EQ("name", "a"), Query.EQ("title",

  • JSP页面中在javascript中定义${base}编译后输出的内容是什么?

    lz后台开发,对前端仅限于编写简单html,so请教一个基础问题,大神勿喷. 如下: 发现许多小伙伴会在页面做如下定义 <script type="text/javascript"> var base="${base}"; </script> 请教下,这个base打印出来的信息是? 如能贴上相关材料出处,不胜感激. --cut-- 落叶丶零落在1970-01-01 16:36:44回答到: 是不是后台传的数据 团伙带头大哥在1970-01-0

  • Summary—【base】(HTML)

    Html知识点: 1. 建议开发人员计算机基本配置 a) 显示所有文件的后缀名* b) 文件的排列方式改为详细信息,并且名称一定要能够全部显示出来 c) 使用小的任务栏 d) 将常用的工具锁定到任务栏中 2. 浏览器与服务器 a) 浏览器与服务器之间存在交互关系 b) 浏览器的内核又被称之为渲染引擎 c) 目前比较主流的浏览器内核: Trident:IE.猎豹浏览器.360浏览器.极速安全浏览器 Gecko:Firefox WebKit:Safari Blink:chrome .opera 参考

  • 从分布式一致性谈到CAP理论、BASE理论

    问题的提出 在计算机科学领域,分布式一致性是一个相当重要且被广泛探索与论证问题,首先来看三种业务场景. 1.火车站售票 假如说我们的终端用户是一位经常坐火车的旅行家,通常他是去车站的售票处购买车票,然后拿着车票去检票口,再坐上火车,开始一段美好的旅行----一切似乎都是那么和谐.想象一下,如果他选择的目的地是杭州,而某一趟开往杭州的火车只剩下最后一张车票,可能在同一时刻,不同售票窗口的另一位乘客也购买了同一张车票.假如说售票系统没有进行一致性的保障,两人都购票成功了.而在检票口检票的时候,其中一

  • Base Enum Properties [AX 2012]

    Base Enum Properties [AX 2012] This topic has not yet been rated - Rate this topic Updated: December 6, 2011 Applies To: Microsoft Dynamics AX 2012 R2, Microsoft Dynamics AX 2012 Feature Pack, Microsoft Dynamics AX 2012 The following table describes

  • Lua5.2中的base库

    Lua中base库里面的接口都是全局可见的,我在 全局环境 一篇里面已经谈到了.在lua5.2中base库增加了2个全局变量和23个函数,这些都可以在lbaselib.c里面找到. 首先增加了两个变量: _G = 当前lua中的全局环境 _VERSION = LUA_VERSION 其中LUA_VERSION是一个宏,在每个版本的Lua中都不一样,定义在lua.h中 可以看到如果我用 print(_VERSION) 打印出来,那么显示的应该是Lua 5.2. 下面按照字典序来解释这23个函数,点

  • 小小&lt;base&gt;标签在web开发中的大作用

    稍微上点规模的项目,通常都会为不同模块或功能的页面,js,css等资源建立不同的路径,或者对不同的servlet等配置不同的虚拟路径.这时,关于各种路径的包含和转向问题长期困扰开发人员. 按照一般的做法,就是要理解web对资源的包含和转向原理,即使:都是从当前所在位置起,根据路径去寻找目标资源. 比如: 1.当前位置在path1下的test1.jsp,在test1.jsp中包含style目录下的css文件drp.css.那么test1.jsp中就应该这么写: <link rel="styl

Tags: