在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
.ctor是构造方法的意思,注意委托其实也是有构造方法的(不过是编译器自动创建的是私有的)貌似它的参数一个是委托引用的方法所属的对象(或Type对象),一个是该方法的指针; 1.属性的概念其实和字段是有一定重合的;C#的属性它不是用来表述某个类具有什么样的行为,而是指某个类具有什么样的成员变量/对象,并且同时指定它可以被外界有什么样的操作; 2.属性也可以是静态属性和私有属性,表示这个属性是属于某个类的,表示这个属性虽然对外提供get或set,但是只是对本类内这个外部范围,不对类外这个外部范围(外部概念可大可小); 3.然后对于抽象编程里,某个接口具有getXx();的方法签名它虽然是getXx()但是它是属于行为层面的,表示它的子类具有获得Xx的行为;这个Xx可以是字段也可以是属性(这里就是它们重合的地方); 4.属性它本质上是一个私有字段加两个方法组成【4.5自动属性出现后这个私有字段仍然存在只不过它应该叫unreachable string _name,然后public string Name {get;set;},这个字段只有该属性能访问反射也弄不出来,类似函数里的局部变量只有该函数能访问】,自动属性的这个私有字段.Net对它做了进一步的隐藏,使得只能通过编译器为属性Name自动创建的两个方法get_Name和set_Name来操作(不信可以去试一下,定义了Name属性且get set后这两个方法不能手动创建),这里之所以要弄成这种很不合标准的方法,其实就是为了和常用标准区别开来,防止用户本身还需要有个GetName方法,然后它可能用下划线get_name或Get_Name,而get_Name正好和这些都不一样是偏僻的方法,只有用户故意捣乱才会这样子写;这样的命名不是为了适应老版本里private string _name的命名风格,就是为了特殊化使得尽可能不和用户可能用到的命名方式一样而导致方法签名重名;这两个方法分别对应get和set,如果只有get那么只会生成get_Name方法;注意,如果不是自动属性,那么是编译器能够感知到的从而不会为该类(该Type)分配一个unreachable字段; 反射里的成员就类似一个和get_Name和set_Name方法的桥接对象,是用来提供给反射操作属性时和平时编码的一致体验,否则我们要在反射里实现this.Name = "mm";就必须获得set_Name(..)方法来操作, 5.对于为属性Name自动生成的两个方法set_Name和get_Name只是反射的时候能看到,但是调试的时候是没法进入的,也没法watch到,因此没法通过调试来看get_Name方法到底是怎么操作那个unreachable访问权限字段的;而虽然反射可以看到这两个方法,但是如果要改属性值还是通过属性去改比较好(这个对这个属性执行写操作会链接到set_Name方法上),这样其实也方便框架获取可序列化的成员; 6.总结(类的组件用Property,类的或类属性的描述参数用Field):字段和属性都是用来描述对象的组成,但是对于那种标准JavaBean(Model层,最多只是实现了ISerializable接口)的空间结构组成要用属性; 7.这里再来进一步区分字段和属性的概念,比如人这个实例类,人有口、鼻子、眼睛、腿、手;然后人具有各种动作,比如跑步,然后跑步它有快慢,加上 people1这个对象它的跑步速度是10, 再举个例子,杯子,杯子它有杯身和背盖(有的可能还有该类杯子特定的勺子),这些都是组件,用Property,但是它还有一些描述性的数据(总算想到一个比较贴切的词),如这个杯子能装多少水,这个就是描述信息; 如果是非自动属性,那么调用Name的反射设置值的时候然后间接调用set_Name这里会传两个参数,一个是this,一个是外部参数,然后set_Name将外部参数赋值到this所处的指针加上要赋值对象的在该对象的内存index上即可,而自动属性其实也是这样子赋值的,只不过自动属性的赋值的时候set_Name只知道要对this + index来赋值,而对非自动属性它还能知道index对应this 字段的名字是什么(一个只知道相对this对象起始位置的偏移量,一个不但知道偏移量还知道偏移到那个位置是this里哪个字段的起点); 或者说一个是没有命名的对象内部的某块空间,一个是有命名的对象的某块空间,显然没有命名的方式是更加精简内存的,否则肯定还需要一些地方用来描述this里每个位置的字段名是什么(类似磁盘里的卷头,用来存储有多少卷,然后每一卷的起始位置是哪里,每一卷的结束位置是哪里,每一卷的命名是什么,这里的磁盘就是对象,每一卷起始就是字段,unreachable的字段是没有卷名的,甚至在卷头里也没有偏移量,这些相对磁盘起始位置的某一卷的起始位置和结束位置存储在了操作方法内部的局部变量里,它在get_Name和set_Name里是两个常量(因为卷头里没有该块空间的位置和描述信息自然就无法反射),所以传入this对象后获得this的其实位置,然后分别加上this的起始位置就得到了那块匿名空间的起始位置和结束位置,然后进行操作; A再举个例子,一栋大楼(对象)里有5层,第一层作为元数据存储区(卷头)不参与存储对象字段,然后我知道要找的字段名如name(对应某一层作为一块空间)【字段名存储在set_Name方法里的局部变量里】,只需要告诉我this指针(大楼起始地址),然后我就跑到一楼查看name的元数据信息包括起止地址类型等,从而知道我要找的name字段在3楼,所以我再跑三楼地板到天花板这部分获取数据或存储数据;这种方式就是非自动属性的实现方式,显然第一楼里需要花一些空间来存储name的一些描述信息; 注意,上面图里的代码的Price是对显式字段price的引用,而且反射是可以获得的,因此编译器这时候就不会创建一个没有元数据的空间来用于set_Price get_Price的操作了,而是set_Price里存储的偏移数据也是指向price这个有元数据的字段上;然后之所以还是需要有这个显式字段的反射信息 是因为这样的显式定义使得price不仅仅可以被set_Price操作,还能被类里的其他方法操作; |
请发表评论