C#关键字partial


前言

partial是分部类型,可以将一个类、接口或结构、方法分成多个部分,便于管理。在编译时会将所有部分组合起来,与普通类并无多大区别,但需要注意累加效应。

分部类

以下情况需要拆分类定义

  • 处理大型项目时,使一个类分布于多个独立文件中可以让多位程序员同时对该类进行处理。

  • 当使用自动生成的源文件时,你可以添加代码而不需要重新创建源文件。 Visual Studio 在创建Windows 窗体、Web 服务包装器代码等时会使用这种方法。 你可以创建使用这些类的代码,这样就不需要修改由Visual Studio生成的文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public partial class Employee
    {
    public void DoWork()
    {
    }
    }

    public partial class Employee
    {
    public void GoToLunch()
    {
    }
    }

累加效应

  1. 分部类各个部分可以指定不同的基接口,最终类型将实现所有分部声明所列出的全部接口。

    1
    2
    3
    4
    5
    6
    partial class Earth : Planet, IRotate { }
    partial class Earth : IRevolve { }

    等同于

    class Earth : Planet, IRotate, IRevolve { }
  2. 分部类编译时会对分部类型定义的属性进行合并

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [SerializableAttribute]
    partial class Moon { }

    [ObsoleteAttribute]
    partial class Moon { }

    等同于

    [SerializableAttribute]
    [ObsoleteAttribute]
    class Moon { }

分部方法

分部类或结构可以包含分部方法。 类的一个部分包含方法的签名。 可以在同一部分或另一部分中定义实现。 如果未提供该实现,则会在编译时删除方法以及对方法的所有调用。
分部方法允许类的某个部分的实现者声明方法。 类的另一部分的实现者可以定义该方法。 在以下两个情形中,此方法很有用:生成样板代码的模板和源生成器。

  • 模板代码:模板保留方法名称和签名,以使生成的代码可以调用方法。 这些方法遵循允许开发人员决定是否实现方法的限制。 如果未实现该方法,编译器会删除方法签名以及对该方法的所有调用。 调用该方法(包括调用中的任何参数计算结果)在运行时没有任何影响。 因此,分部类中的任何代码都可以随意地使用分部方法,即使未提供实现也是如此。 调用但不实现该方法不会导致编译时错误或运行时错误。
  • 源生成器:源生成器提供方法的实现。 开发人员可以添加方法声明(通常由源生成器读取属性)。 开发人员可以编写调用这些方法的代码。 源生成器在编译过程中运行并提供实现。 在这种情况下,不会遵循不经常实现的分部方法的限制。
1
2
3
4
5
6
7
8
// Definition in file1.cs
partial void OnNameChanged();

// Implementation in file2.cs
partial void OnNameChanged()
{
// method body
}

使用限制

  1. partial 修饰符不可用于委托或枚举声明中。
  2. 同一个类型的各个部分必须有修饰符partial。
  3. 要成为同一类型的各个部分的所有分部类型定义都必须在同一程序集和同一模块(.exe 或 .dll 文件)中进行定义。 分部定义不能跨越多个模块。
  4. 你可以为已定义并实现的分部方法生成委托,但不能为已经定义但未实现的分部方法生成委托。