第10章 属性
10.1 无参属性
无参属性(parameterless property)就是通常说的属性(property)。CLR支持静态属性、实例属性和虚属性。属性可以标记任何的访问限定修饰符,也可以被定义在接口中。属性不能被重载
定义一个同时带get和set方法的属性时,编译器会在生成的托管模块中产生一个表示属性的get访问器方法和一个表示属性的set访问器方法,以及一个位于托管模块元数据中的属性定义,其中包括了一些标记和属性的类型,并有一个对get和set访问器方法的引用,我们可以用System.Reflection.PropertyInfo来获取这些元数据信息
C#编译器通过在我们指定的属性名前添加get_和set_来自动为生成的访问器方法命名
对于简单的get和set访问器方法,JIT编译器会将代码进行内联(inline)处理,这样使用属性时就不会再有运行时性能损失
10.2 含参属性
含参属性(parameterful property)是CLR支持的一种get访问器方法接受一个或多个参数的属性(无参属性的get访问器方法没有参数,set访问器方法有一个参数value),C#中称之为索引器(indexer),VB中称之为默认属性(default property),而托管扩展C++则称之为索引属性(index property)
C#中索引器可以用类似数组的语法来访问。一个类型可以提供多个重载的索引器,只要签名不同即可,这与无参属性不同。所有的索引器都必须至少有一个参数。下面是一个索引器定义的例子:
public String this[Int32 i] { get { ... } set { ... } }
CLR本身并不区分无参属性和含参属性,对CLR来讲属性仅仅是定义在类型中的一对或一个方法而已。C#要求用this[...]作为表达索引器的语法仅仅是C#编译器选择的方案而已,这意味着C#只允许我们在对象实例上定义索引器。虽然CLR支持静态含参属性,但C#没有为我们提供定义静态索引器的语法
因为CLR对待含参属性和无参属性的方式是一样的,所以编译器在编译含有索引器的类型时生成的托管模块中的内容与无参属性相同
C#编译器在编译索引器时自动为访问器方法命名为get_Item和set_Item(应该可以定义一个无参属性名为Item,因为无参属性的访问器方法的参数与含参属性肯定不同),但允许我们通过在索引器上应用System.Runtime.CompilerServices.IndexerNameAttribute特性来改变编译器自动产生的名称,这样可以方便我们设计的索引器被其他语言用较友好的具体访问器方法名来访问。System.String类型就是一个改变了索引器名称的例子,它的索引器名称为Chars而非Item
然而即使我们可以通过特性来改变自动产生的名称,C#仍然不允许我们定义多个名称不同但签名相同的索引器,因为它不能通过名称来引用索引器。如果其他语言的开发人员在一个类型中定义了多个不同名称的含参属性,该类型必须应用System.Reflection.DefaultMemberAttribute特性来选择一个含参属性方法名作为默认的属性,才能让C#正常访问