第 6 章 类型和成员基础
第 6 章 类型和成员基础
NyxX第 6 章 类型和成员基础
本章内容
6.1 类型的各种成员
类型中可定义 0 个或多个以下种类的成员。
常量 常量是指出数据值恒定不变的符号。这种符号使代码更易阅读和维护。常量总与类型关联,不于类型的实例关联。常量逻辑上总是静态成员。相关内容在第 7 章“常量和字段”讨论。
字段 字段表示只读或可读的数据值。字段可以是静态的;这种字段被认为是类型状态的一部分。字段也可以是实例(非静态);这种字段被认为是对象状态的一部分。强烈建议将字段声明为私有,防止类型或对象的状态被类型外部的代码破坏。相关内容在第 7 章讨论。
实例构造器 实例构造器是将新对象的实例字段初始化为良好初始状态的特殊方法。相关内容在第 8 章“方法”讨论。
类型构造器 类型构造器是将类型的静态字段初始化为良好初始状态的特殊方法。相关内容在第 8 章讨论。
方法 方法是更改或查询类型或对象状态的函数。作用于类型称为
静态方法,作用于对象称为实例方法。方法通常要读写类型或对象的字段。相关内容在第 8 章讨论。操作符重载 操作符重载实际是方法,定义了当操作符作用于对象时,应该如何操作该对象。由于不是所有编程语言都支持操作符重载,所以操作符重载方法不是“公共语言规范”(Common Language Specification, CLS)的一部分。相关内容在第 8 章讨论。
转换操作符 转换操作符是定义如何隐式或显式将对象从一种类型转型为另一种类型的方法。和操作符重载方法一样,并不是所有编程语言都支持转换操作符,所以不是 CLS 的一部分。相关内容在第 8 章讨论。
属性 属性允许用简单的、字段风格的语法设置或查询类型或对象的逻辑状态,同时保证状态不被破坏。作用于类型称为静态属性,作用于对象称为实例属性。属性可以无参(非常普遍),也可以有多个参数(相当少见,但集合类用得多)。相关内容在第 10 章 “属性”讨论。
事件 静态事件允许类型向一个或多个静态或实例方法发送通知。实例(非静态)事件允许对象向一个或多个静态或实例方法发送通知。引发事件通常是为了响应提供事件的类型或对象的状态的改变。事件包含两个方法,允许静态或实例方法登记或注销对该事件的关注。除了这两个方法,事件通常还用一个委托字段来维护已登记的方法集。相关内容在第 11 章“事件”讨论。
类型 类型可定义其他嵌套类型。通常用这个办法将大的、复杂的类型分解成更小的构建单元(building block)以简化实现。
6.2 类型的可见性
可将类型的可见性指定为 public 或 internal。public类型不仅对定义程序集中的所有代码可见,还对其他程序集中的代码可见。
internal 类型则仅对定义程序集中的所有代码可见,对其他程序集中的代码不可见。
友元程序集
生成程序集时,可用 System.Runtime.CompilerServices 命名空间中的 InternalsVisibleTo 特性标明它认为是“友元”的其他程序集。该特性获取标识友元程序集名称和公钥的字符串参数。注意当程序集认了“友元”之后,友元程序集就能访问该程序集中的所有 internal 类型,以及这些类型的 internal 成员。下例展示一个程序集如何将两个强命名程序集 “Wintellect” 和 “Microsoft” 指定为友元程序集:
1 | using System; |
6.3 成员的可访问性
表 6-1 成员的可访问性
| CLR术语 | C#术语 | 描述 |
|---|---|---|
Private |
private |
成员只能由定义类型或任何嵌套类型中的方法访问 |
Family |
protected |
成员只能由定义类型、任何嵌套类型或者不管在什么程序集中的派生类型中的方法访问 |
Family and Assembly |
(不支持) | 成员只能由定义类型、任何嵌套类型或者同一程序集中定义的任何派生类型中的方法访问 |
Assembly |
internal |
成员只能由定义程序集中的方法访问 |
Family or Assembly |
protected internal |
成员可由任何嵌套类型、任何派生类型(不管在什么程序集)或者定义程序集中的任何方法访问 |
Public |
public |
成员可由任何程序集的任何方法访问 |
6.4 静态类
C# 编译器对静态类进行了如下限制。
- 静态类必须直接从基类
System.Object派生,从其他任何基类派生都没有意义。继承只适用于对象,而你不能创建静态类的实例。 - 静态类不能实现任何接口,这是因为只有使用类型的实例时,才可调用类的接口方法。
- 静态类只能定义静态成员(字段、方法、属性和事件),任何实例成员都会导致编译器报错。
- 静态类不能作为字段、方法参数或局部变量使用,因为它们都代表引用了实例的变量,而这是不允许的。编译器检测到任何这样的用法都会报错。
6.5 分部类、结构和接口
要将 partial 关键字应用于所有文件中的类型。这些文件编译到一起时,编译器会合并代码,在最后的.exe 或 .dll 程序文件(或 .netmodule 模块文件)中生成单个类型。
“分部类型”功能完全由 C# 编译器实现,CLR 对该功能一无所知
6.6 组件、多态和版本控制
6.6.1 CLR 如何调用虚方法、属性和事件
在类型上执行操作,称为静态方法;在类型的实例上执行操作,称为非静态方法。
CLR 提供两个方法调用指令
call
该 IL 指令可调用静态方法、实例方法和虚方法。用 call 指令调用静态方法,必须指定方法的定义类型。用 call 指令调用实例方法或虚方法,必须指定引用了对象的变量。call指令假定该变量不为null。callvirt
用于调用实例方法和虚方法,但不能调用静态方法。对于调用非虚实例方法,变量的类型确定了方法的定义类型。而调用虚实例方法时,CLR会根据调用对象的实际类型进行多态调用。编译这个调用时,JIT 编译器会生成代码来验证变量的值是不是null。





