第十章 属性
CLR提供了两种属性:无参属性和含参属性。前者通常被称为属性(property),后者C#称为索引器。
Ø 10.1 无参属性
将所有字段的访问限制都设为私有方式或者至少是保护方式——永远不要设为共有方式,然后再以方法的形式让用户读取或者设置对象的状态信息。封装了对字段访问的方法典型地被称为访问器方法(accessor method)。访问器方法可以选择执行任何的数据合理性检查来确保对象的状态不被破坏。
访问器方法的缺点:
1. 需要编写更多的代码,因为必须要实现额外的方法
2. 类型的用户必须调用方法而不是简单地引用字段名称
CLR支持静态属性,实例属性和虚属性。另外属性可以标记任何的访问修饰符,也可以定义在接口中。
每个属性都有一个名称和一个类型,属性不能被重载。
定义属性会在生成的托管模块中产生以下三项:
1. 一个表示属性的get访问器的方法。只有在为属性定义了get访问器方法时,才有这一项。
2. 一个表示属性的set访问器的方法。只有在为属性定义了set访问器方法时,才有这一项。
3. 一个位于托管模块元数据中的属性的定义,不管是只读,只写,或者读写属性都有这一项。
可以通过System.Reflection.PropertyInfo类来获取属性。
程序运行时,属性的底层处理:
对于简单的get和set访问器方法,JIT编译器会将代码进行内联处理,这样使用属性时就不会再有运行时的性能损失。内联会将一个方法(或者访问器方法)内的代码直接编译到调用它们的方法中,从而消除了调用方法时的运行时负担,但它的代价是编译后的方法代码会变得较为庞大。由于属性的访问器方法通常包含有很少的代码,所以内联它们会使代码变得更小,执行效率也更高。
Ø 10.2 含参属性
索引器必须至少有一个参数,也可以有多个。这些参数(以及返回值)可以是任意类型。
与无参属性的set访问器类似,索引器的set访问器方法也有一个隐含的参数(C#称之为value),该参数表示“被索引元素”期望的新值。
定义含参属性也会在生成的托管模块中产生以下三项:
1. 一个表示含参属性的get访问器的方法。只有在为含参属性定义了get访问器方法时,才有这一项。
2. 一个表示含参属性的set访问器的方法。只有在为含参属性定义了set访问器方法时,才有这一项。
3. 一个位于托管模块元数据中的属性的定义,不管是只读,只写或者读写属性都有这一项。不存在特别的含参属性数据定义表,因为对CLR来讲,含参属性就是属性。
一个类型可以定义多个索引器,前提是这些索引器的参数集合各不相同。
C#将索引器看作是重载[]操作符的一种方式,而该操作符不能用来辨析具有不同方法名称的含参属性。
对于CLR来讲,无参属性和含参属性之间没有任何区别,所以我们同样可以使用System.Reflection.PropertyInfo类来查找一个含参属性与它的访问器方法之间的关联关系。