CLR via C# 方法 分部方法

假定用某个工具生成了包含类型定义的C#源代码文件,工具知道你想在代码的某些位置定制类型的行为。正常情况下,是让工具生成的代码调用虚方法来进行定制。工具生成的代码还必须包含虚方法的定义。另外,这些方法的实现是什么事情都不做,直接返回了事。现在,如果想定制类的行为,就必须从基类派生并定义自己的类,重写虚方法来实现自己想要的行为。

举例:

CLR via C# 方法 分部方法

遗憾的是,上述代码存在两个问题:

1.类型必须是非密封类。这个技术不能用于密封类,也不能用于值类型(值类型隐式密封)。此外,这个技术不能用于静态方法,因为静态方法不能重写。

2.效率问题。定义一个类型只是为了重写一个方法,这会浪费少量系统资源。另外,即使不想重写OnNameChange的行为,基类代码仍需调用一个什么都不做、直接就返回的虚方法。另外,无论OnNameChange是否访问传给它的实参,编译器都会生成对ToUpper进行调用的IL代码。

//--

利用C#的 分部方法 功能,可以在解决上述问题的同时覆盖类的行为。

CLR via C# 方法 分部方法

注意:

1.类现在密封(虽然并非一定如此)。事实上,类可以是静态类,甚至可以是值类型。

2.工具和开发者所生成的代码真的是hi一个类型定义的两个部分。

3.工具生成的代码包含分部方法的声明。要用partial关键字标记,无主体。

4.开发者生成的代码实现这个声明。该方法也要用partial关键字标记,有主体。

//--

好处,在新的源代码文件中生成新的代码,但你自己的代码时存储在一个单独的文件中的,不会受到影响。

分部方法还提供了另一个巨大的提升。如果不想修改工具类生成的类型的行为,那么根本不需要提供自己的源代码文件。也就是说,如果没有实现分部方法,编译器不会生成任何代表分部方法的元数据。此外,编译器不会生成任何调用分部方法的IL指令。

结果就是更少的元数据/IL,运行时的性能得到了提升。

//--

规则和原则

1.它们只能在分部类或结构中声明。

2.分部方法的返回类型始终是void,任何参数都不能用out修饰符来标记。之所以有这两个限制,是因为方法在运行时可能是不存在的,所以不能将变量初始化为方法也许会返回的东西。类似的,不允许out参数是因为 方法必须初始化它,而方法可能不存在。分部方法可以有ref参数,可以是泛型方法,可以是实例或静态方法,而且可标记为unsafe。

3.当然,分部方法的声明和实现必须具有完全一致的签名。如果两者都应用了定制特性,编译器会合并两个方法的特性。应用于参数的任何特性也会合并。

4.如果没有对应地实现分部,便不能再代码中创建一个委托来引用这个分部方法。同样是由于方法在运行时不存在。

5.分部方法总是被视为private方法,但C#编译器禁止在分部方法声明之前添加private关键字。