CLR via C#笔记——第六章

类型和成员基础

《CLR via C#》第六章:类型和成员基础

类型的各种成员

类型中可定义0个或多个以下种类的成员:

  • 常量,指出数据值恒定不变的符号。总是与类型关联,不与类型的实例关联,总是静态成员。
  • 字段,表示只读或可读/可写的数据值。字段可以是静态的(类型状态的一部分),也可以是实例(对象状态的一部分)。建议将字段声明为私有,防止被类型外部的代码破坏。
  • 实例构造器,将新对象的实例字段初始化为良好初始状态的特殊方法。
  • 类型构造器,将新类型的静态字段初始化为良好初始状态的特殊方法。
  • 方法,更改或查询类型或对象状态的函数。作用于类型称为静态方法,作用于对象称为实例方法。
  • 操作符重载,定义了当操作符作用于对象时,应如何操作该对象,实际是方法。不是CLS的一部分。
  • 转换操作符,定义如何隐式或显式将对象从一个类型转型为另一种类型的方法。不是CLS的一部分。
  • 属性,允许用简单的、字段风格的语法设置或查询类型或对象的逻辑状态,同时保证状态不被破坏。作用于类型称为静态属性,作用于对象成为实例属性。可以无参也可以多参(集合类中多见)。
  • 事件,静态事件允许类型向一个或多个静态或实例方法发送通知。实例事件允许对象向一个或多个静态或实例方法发送通知。事件包含两个方法,允许静态或实例方法登记或注销对该事件的关注。除此之外,事件通常还用一个委托字段来维护已登记的方法集。
  • 类型,可定义其他嵌套类型,以将复杂的类型分解为更小的构建单元。

类型的可见性

public不仅对定义程序集中的所有代码可见,还对其他程序集中的代码可见。
internal类型仅对定义程序及中的代码可见。
不显式指定时,C#编译器默认指定为internal。

友元程序集

生成程序集时可用System.Runtime.CompilerServices命名空间中的InternalsVisibleTo特性标明它认为是友元的其他程序集。

[assembly:InternalsVisibleTo("Wintellect, PublicKey=1234...abc")]  
internal sealed class SomeInternalType { ... }  

C#编译器在编译友元程序集(不含InternalsVisibleTo特性的程序集)时要求使用编译器开关/out:。这样编译器可以知道准备编译的程序集的名称,从而判断生成的程序集是否为友元程序集。
如果使用C#编译器的/t:module开关编译模块,而该模块将称为某个友元程序集的一部分,则需要使用C#编译器的/moduleassemblyname:开关来编译该模块,告诉编译器该模块将成为哪个程序集的一部分。

成员的可访问性

定义类型的成员时,可指定成员的可访问性。
CLR术语(C#术语)
Private(private)
Family(protected)
Family and Assembly(不支持)
Assembly(internal)
Family or Assembly(protected internal)
Public(public)
派生类型重写基类型定义的成员时,C#要求原始成员与重写成员具有相同的可访问性(C#限制,非CLR限制)。CLR允许放宽但不允许收紧成员的可访问性限制。

静态类

永远不需要实例化。
只有static成员,组合一组相关成员。

  • 静态类必须直接从基类System.Object派生。
  • 静态类不能实现任何接口。
  • 静态类只能定义静态成员(字段、方法、属性和事件)。
  • 静态类不能作为字段、方法参数或局部变量使用。

分部类、结构和接口

partial关键字告诉C#编译器,类、结构或接口的定义源代码可能分散到一个或多个源代码文件中,其优势在于:

  • 源代码控制
  • 在同一个文件中将类或结构分解成不能的逻辑单元
  • 代码拆分

组件、多态和版本控制

组件软件编程(Component Software Programming,CSP)具有以下特点:

  • 组件(.NET Framework称为程序集)有“已经发布”的意思
  • 组件有自己的标识(名称、版本、语言文化和公钥)
  • 组件永远维持自己的标识
  • 组件清楚指明它所依赖的组件(引用元数据表)
  • 组件应编档它的类和成员。C#通过源代码内的XML文档和编译器的/doc命令行开关提供该功能
  • 组件必须指定它需要的安全权限。CLR的代码访问安全性机制提供该功能
  • 组件要发布在任何“维护版本”中都不会改变的接口(对象模型)。

C#提供了5个能影响组件版本控制的关键字,可应用于类型或类型成员。

  • abstract,表示为了构造派生类型的实例,派生类型必须重写并实现这个成员
  • virtual,表示这个成员可由派生类型重写
  • override,表示派生类型正重写基类型成员
  • sealed,表示改类型不能用作基类型;表示这个成员不能被派生类型重写,只能将该关键字应用于重写虚方法的方法
  • new,应用于嵌套类型、方法、属性、事件、常量或字段时,表示该成员与基类中相似的成员无任何关系
CLR如何调用虚方法、属性和事件

在类型上执行操作称为静态方法,在类型的实例上执行操作称为非惊天方法。
CLR提供两个方法调用指令:

  • call,该IL指令可调用静态方法、实例方法和虚方法。常用于以非虚方式调用虚方法。
  • callvirt,该IL指令可调用实例方法和虚方法,不能调用静态方法。由于要生成代码来验证变量值是否为null,callvirt执行速度比call稍慢。
合理使用类型的可见性和成员的可见性

密封类的好处:

  • 版本控制
  • 性能
  • 安全性和可预测性
    一些建议:
  • 定义类时,除非确定杠幺将其作为基类,并允许派生类对它进行特化,否则总是显式指定为sealed类。
  • 类的内部,将数据字段定义为private。
  • 类的内部,总是将自己的方法、属性和事件定义为private和非虚。
  • 当算法的实现开始变得复杂时,定义一些辅助类型来封装独立的功能。
对类型进行版本控制时虚方法的处理

略(virtual,override,new关键字)