分部类在编译期被彻底合并,生成il与手写完整类完全一致,运行时零开销、零反射痕迹;必须满足partial关键字全出现、同程序集、同命名空间、访问修饰符一致、抽象/密封统一、基类唯一指定等硬性约束。

分部类不是语法糖,也不是可有可无的装饰——它在编译期就被彻底合并,最终生成的 IL 和你手写一个完整类完全一样。只要用法合规,运行时零开销、零反射痕迹。
partial 类必须满足哪些硬性约束
编译器对 partial 类的检查非常严格,不满足任一条件就会报错,而不是静默降级:
-
partial关键字必须出现在每个部分的声明前,缺一不可 - 所有部分必须在同一个程序集(.exe 或 .dll)内,跨程序集拆分无效
- 所有部分必须位于同一命名空间,哪怕只差一级嵌套也不行
- 可访问性修饰符必须一致:不能一个写
public partial class A,另一个写internal partial class A - 若任意一部分加了
abstract或sealed,整个类型即被标记为抽象或密封,其他部分不能再改 - 基类只能在一个部分中指定,比如
partial class A : Base,其余部分省略基类即可,但不能写成partial class A : OtherBase
partial void 方法为什么必须返回 void 且不能有访问修饰符
分部方法本质是“可选钩子”:签名由框架/设计器生成,实现由开发者决定是否提供。编译器会在生成阶段做两件事:
- 如果某
partial void OnSave()只有声明没有实现,整行调用会被直接剔除,不生成任何 IL - 如果提供了实现,就按普通私有方法处理,但不允许加
public、protected等修饰符——因为它的存在与否本就不该影响外部可见性 - 返回值强制为
void是为了确保调用方无需处理返回逻辑;若有返回值,未实现时编译器无法决定默认返回什么 - 特性(如
[Obsolete])也不能加在分部方法上,否则编译失败
Windows Forms 场景下 partial 的真实分工逻辑
你在 VS 里拖控件生成的 Form1.Designer.cs 和手动写的 Form1.cs 就是典型的 partial 协作模式:
-
Form1.Designer.cs负责控件字段声明、InitializeComponent()初始化逻辑,由设计器自动生成,你不该手动修改 -
Form1.cs负责事件处理、业务逻辑、自定义方法,你可以自由增删改,不影响设计器文件 - 两者通过
public partial class Form1 : Form关联,编译时合并为一个Form1类型 - 如果你误删了其中一个文件里的
partial,或者把两个文件放在不同命名空间,VS 会立刻报 CS0260:“缺少 partial 修饰符”或“类型已定义”
C# 13+ 新增的 partial property 和 partial constructor 怎么用
从 C# 13 开始,partial 不再局限于类和方法,还能用于属性和构造函数,但使用限制更细:
-
partial int Age { get; set; }声明可在一部分,partial int Age { get => _age; set => _age = value; }实现可在另一部分 -
partial void PartialMethod();和partial void PartialMethod() { ... }必须成对出现才有效;而partial int Prop { get; }声明后,另一部分可以只实现get,也可以只实现set,甚至两者都实现 - 分部实例构造函数(C# 14+)允许把初始化逻辑拆开,比如一个部分处理依赖注入参数,另一个处理 UI 绑定,但所有分部构造函数必须有相同签名,且不能有
this(...)或base(...)调用 - 注意:分部属性不支持自动属性初始化器(
partial int X { get; set; } = 42;是非法的)
最容易被忽略的是:分部类型的 XML 文档注释会自动合并,但如果你在两个文件里都写了 /// <summary></summary>,最终生成的文档只会取第一个;接口实现列表、泛型约束、特性也都是“叠加”而非“覆盖”,这点在调试反射行为或生成 API 文档时特别关键。










