利用partial关键字声明分部类和分部方法

时间:2021-11-04 16:23:01

一、分部类

1、分部类的定义:简单的说,分部类就是把一个类拆分成多个类,每个类文件只包含其中的一部分,类、结构、接口、方法都可以拆分,在定义的时候加上partial修饰符。

注意:分部类必须属于同一命名空间。类名必须相同。

2、分部类的应用:

  • 分部类对于代码生成或修改工具来说意义重大。使用分部类,这些工具操作的文件可以独立于开发者正在人工编码的文件。

例如:假如一个代码生成工具能根据数据库中的Person表为Person类生成对应的Person.Designer.cs文件。这个工具将检查表的内容,并为表中的每一列都创建属性。问题在于,这个工具经常都不能生成一些必要的验证逻辑,因为这些验证逻辑要依赖于没有嵌入数据库表定义的业务规则。在这种情况下,Person类的开发者需要自己添加验证逻辑。Person.Designer.cs是不好直接修改的,因为假如文件被重新生成(例如,为了适应数据库中新增的一个列而重新生成文件),所做的更改就会丢失。在这种情况下,Person类的代码结构应独立出来,是生成的代码在一个文件中,定制的代码(带有业务规则)则在另一个文件中。后者不受任何重新生成动作的影响。

  • 将每个嵌套类都放到他们自己的文件中。这是为了与编程规范”将每个类定义都放到它自己的文件中“保持一致。

注意:分部类不允许对编译好的类(其他程序集中的类)进行扩展。只能利用分部类在同一个程序集中经一个类的实现分解到多个文件中。

二、分部方法

  • 分部方法只能存在于分部类中,必须加上partial,不能有访问修饰符,因此是隐式私有的。其主旨是为了代码的生成提供方便。
  • 分部方法允许声明一个方法而不需要一个实现。如果包含了可选的实现,这个实现可以放到某个姊妹分部类的定义中(可能在一个单独的文件中)。
  • 分部方法使程序能调用未实现的方法,而不会发生编译错误。如果程序中未提供分部方法的实现,则编译器会自动移除方法签名,以及所有对该方法的调用。也就是说,如果没有为一个分部方法提供实现,CIL中不会出现分部方法的任何踪迹。这样,在保持代码尽量小的同时,还保持了高地灵活性。
  • 分部方法的返回值类型必须是void。原因:如果不是返回null,同时没有提供实现,那么调用一个未实现的方法,返回什么才合理呢?为了避免对返回值进行任何无端的猜测,c#的设计者决定只允许方法返回void。类似的,out参数在分部方法中是不允许的。如果需要一个返回值,可以使用ref参数。

三、局部类型

1.局部类型适用于以下情况:

(1) 类型特别大,不宜放在一个文件中实现。
(2) 一个类型中的一部分代码为自动化工具生成的代码,不宜与我们自己编写的代码混合在一起。
(3) 需要多人合作编写一个类

2. 局部类型的限制

(1) 局部类型只适用于类、接口、结构,不支持委托和枚举。
(2) 同一个类型的各个部分必须都有修饰符 partial。
(3) 使用局部类型时,一个类型的各个部分必须位于相同的命名空间中。
(4) 一个类型的各个部分必须被同时编译。

3. 局部类型的注意点

(1) 关键字partial是一个上下文关键字,只有和 class、struct、interface 放在一起时才有关键字的含义。因此partial的引入不会影响现有代码中名称为partial的变量。
(2) 局部类型的各个部分一般是分开放在几个不同的.cs文件中,但C#编译器允许我们将他们放在同一文件中。

4. 局部类型的应用特性

在局部类型上的特性具有“累加”效应。

[Attribute1, Attribute2("Hello")]
partial class Class1{}

[Attribute3, Attribute2("Exit")]
partial class Class1{}

相当于

[Attribute1, Attribute2("Hello"), Attribute3, Attribute2("Exit")]
class Class1 {}

注:Attribute2属性允许在类上多次使用。

5. 局部类型上的修饰符

(1) 一个类型的各个部分上的访问修饰符必须维持一致性。
(2) 如果一个类型有一个部分使用了abstract修饰符,那么整个类都将被视为抽象类。
(3) 如果一个类型有一个部分使用了 sealed 修饰符,那么整个类都将被视为密封类。
(4) 一个类的各个部分不能使用相互矛盾的修饰符,比如不能在一个部分上使用abstract,又在另一个部分上使用sealed。

6. 局部类型的基类和接口

(1) 一个类型的各个部分上指定的基类必须一致。某个部分可以不指定基类,但如果指定,则必须相同。
(2) 局部类型上的接口具有“累加”效应。

partial class Class2: Iinterface1, Iinterface2 {}
partial class Class2: Iinterface3 {}
partial class Class2: Iinterface2 {}

相当于

class Class2: Iinterface1, Iinterface2, Iinterface3 {}