第六章 类型和成员基础
本章内容
类型成员的种类
类型的可见性
成员的可访问性
静态类
部分类、结构和接口
组件、多态和版本控制
在第Ⅱ部分“类型的使用”中,我们重点介绍类型以及任何类型的所有实例通用的操作,并阐述如何将类型划分为引用类型和值类型。在本章及本部分的后续章节,我们将示范如何使用可以在类型中定义的各种成员来设计类型。从第7章到第10章,我们将详细讨论各种成员。
6.1 类型成员的种类
类型可以定义0个或者多个下述类型的成员:
常量(第7章) 常量就是一个用来标识数据值恒定不变的符号。这些符号通常用于使代码更容易阅读和维护。常量通常与类型关联,而不与类型的实例关联。从逻辑上讲,常量通常是静态成员。
字段(第7章) 字段表示一个只读或可读可写的数据值。字段可以是静态的;这种情况下,字段是类型状态的一部分;字段也可以是实例(非静态的),这种情况下,字段是对象状态的一部分。强烈建议将字段声明为私有字段,以免被该类型外部的代码破坏类型或者对象的状态。
实例构造器(第8章) 实例构造器是一种将新对象的实例字段初始化为有效初始状态的特殊方法。
类型构造器(第8章) 类型构造器是一种将类型的静态字段初始化为有效初始状态的特殊方法。
方法(第8章) 方法是一个执行改变或者查询类型状态(静态方法)或者对象状态(实例方法)操作的函数。方法通常读或写类型或者对象的字段。
操作符重载(第8章) 操作符重载指对对象应用特定操作符时定义对象如何操作的方法。因为并不是所有的编程语言都支持操作符重载方法,所以操作符重载方法不属于公共语言规范(Common Language Specification,CLS)。
转换操作符(第8章) 转换操作符是定义如何隐式或者显式地将对象从一种类型转换(或强制转换)到另一种类型的方法。和操作符重载方法一样,并不是所有的编程语言都支持转换操作符,因此转换操作符也不属于CLS。
属性(第9章) 属性是指允许使用一个简单的、字段形式的语法来设置或者查询类型(静态属性)或对象(实例属性)的部分逻辑状态,并且保证该状态不被破坏的一种机制。属性可以没有参数(这种情况非常普遍),也可以有多个参数(这种情况相当少见,但是经常在集合类(collection class)中使用)。
事件(第10章) 静态事件(static event)是指允许类型为监听类型(listening type)或者监听对象(listening object)发送通知的机制。实例(非静态)事件(instance event)是指允许对象为监听类型或者监听对象发送通知的机制。事件的触发通常是为了响应产生事件的类型或者对象的状态发生的改变。事件包含两个方法,允许类型或者对象(通常称为监听者(listener))订阅或者注销事件。除了这两个方法,事件通常还使用一个委托字段(delegate field)来维护已订阅该事件的监听者。
类型 类型可以在类型内部嵌套地定义其他类型。通常使用这个方法将一个大的、复杂的类型分解成小的构建块(building block),以此来简化实现。
再次声明本章的目的不是为了详细地描述各种类型的成员,而是阐明各种类型的成员都拥有的共性,为后面的章节打一个基础。
无论使用什么编程语言,相应的编译器都必须能够处理前述列表中所有类型的成员的源代码,并且能够为每个成员生成元数据(metadata)和中间语言(Intermediate Language,IL)代码。元数据的格式与源代码所使用的编程语言无关,因此元数据的格式都是相同的,这使得CLR成为名副其实的“公共语言运行库”(Common Language Runtime,CLR)。元数据是所有语言都可以生成和使用的公共信息,它使某一编程语言编写的代码可以无缝地访问另一个完全不同的编程语言编写的代码。
CLR同样也使用公共元数据格式,CLR用它们决定常量、字段、构造器、方法、属性和事件的行为在运行时如何表现。简单地说,元数据就是整个Microsoft.NET Framework开发平台的关键,它允许编程语言、类型和对象之间的无缝集成。
下面的C#代码示范了包含所有可能的成员的类型定义,这段代码可以通过编译(不过会出现警告信息),但是它并不能代表我们通常所要创建的类型,因为这段代码中定义的大部分方法根本没有做任何有价值的事情。这里仅仅是为了示范编译器如何将类型及其成员转换成元数据。再次声明,在后续章节中我们将对这些成员逐一进行讨论。
using System;
public sealed class SomeType { // 1
//嵌套类
private class SomeNestedType{} // 2
//常量、只读字段和静态读写字段
private const Int32 SomeConstant = 1; // 3
private readonly Int32 SomeReadOnlyField = 2;// 4
private static Int32 SomeReadWriteField = 3; // 5
//类型构造器
static SomeType(){} // 6
//实例构造器
public SomeType(){} // 7
public SomeType(Int32x){} // 8
//实例方法和静态方法
private String InstanceMethod() {returnnull;}// 9
public static void Main(){} //10
//实例无参属性
public Int32 SomeProp{ //11
get{ return0; } //12
set{ } //13
}
//实例有参属性
public Int32 this[String s]{ //14
get{return0;} //15
set{} //16
}
//实例事件
public event EventHandler SomeEvent; //17
}
|
如果编译刚才定义的类型,然后用ILDasm.exe来查看得到的元数据,将看到如图6.1中所示的输出结果。
![]() |
| 图6.1 上述代码的元数据在ILDasm.exe中的显示输出 |
注意,编译器为定义在源代码中的所有成员都产生了相关的元数据。实际上,对于其中的一些成员编译器,还为它们产生了额外的成员以及额外的元数据。例如,事件成员(代码中编号为17)使编译器生成了一个字段、两个方法及一些额外的元数据。这里并不希望大家能完全理解其中的内容。但是,当学习完后面几章内容后,希望大家能回顾一下这个范例,看看成员是如何定义的,以及对编译器生成的元数据有何影响。
| 回书目 上一节 下一节 |