第10章:命名规范(建议122-139)
覆盖namespace/assembly/type/interface/generic/enum命名,公开与私有成员、property/boolean/version命名,以及delegate、event、EventArgs和handler组合。
学习目标
- 能设计namespace、assembly、type、interface、generic parameter和enum naming hierarchy,避免platform collision并表达domain ownership
- 能比较PascalCase、camelCase、prefix、property/boolean/version suffix在不同visibility和call site中的语义
- 能设计delegate/EventArgs/event/handler整条命名链,判断before/after tense、unsubscribe与UI composition约定
机制总览
第10章:命名规范(建议122-139):机制路径
- 1
为什么命名规范是一套Search和Compatibilit…
好名字让reader不打开implementation也能预测type角色、boolean真值、event时机和module owner;一致casing让IDE、analyzer与API docs形成统一索引。命名并非追求最长描述,而是在作用域内消除歧义,并给未来新增type/version留下空间。
- 2
Namespace、Type与Generic Names(…
dot分隔稳定层级,例如 Company.Product.Domain.Feature ;每段使用PascalCase并代表真实ownership/概念,不机械映射每个folder。层级太深增加using与移动成本, Common.Helpers.Utils 则几乎没有semantic signal。
- 3
Member、Boolean与Version Names(…
public/protected types、methods、properties、events使用PascalCase,与.NET ecosystem一致;acronym按项目/FCL style处理,例如 HttpClient 而非 HTTPClient 。用formatter/analyzer自动执行,不靠review争论大小写。
章级决策实验
第10章:命名规范(建议122-139):机制与证据
切换《第10章:命名规范(建议122-139)》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。
选择推理阶段
当前阶段 · 为什么命名规范是一套Search和Compatibilit…
好名字让reader不打开implementation也能预测type角色、boolean真值、event时机和module owner;一致casing让IDE、analyzer与API docs形成统一索引。命名并非追求最长描述,而是在作用域内消除歧义,并给未来新增type/version留下空间。
可核验证据
固定当前 .NET、语言版本和输入规模,用编译诊断、分析器、自动化测试、基准或安全失败样本复核「为什么命名规范是一套Search和Compatibilit…」的收益与反例。
学完《第10章:命名规范(建议122-139)》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。
失效—证据矩阵
第10章:命名规范(建议122-139):失效与核验
为什么命名规范是一套Search和Compatibilit…
典型失效
若把「为什么命名规范是一套Search和Compatibilit…」当作脱离版本与上下文的硬规则,可能用过时的优化或风格替换了更重要的正确性、安全性与可维护性约束。
核验证据
固定当前 .NET、语言版本和输入规模,用编译诊断、分析器、自动化测试、基准或安全失败样本复核「为什么命名规范是一套Search和Compatibilit…」的收益与反例。
Namespace、Type与Generic Names(…
典型失效
若把「Namespace、Type与Generic Names(…」当作脱离版本与上下文的硬规则,可能用过时的优化或风格替换了更重要的正确性、安全性与可维护性约束。
核验证据
固定当前 .NET、语言版本和输入规模,用编译诊断、分析器、自动化测试、基准或安全失败样本复核「Namespace、Type与Generic Names(…」的收益与反例。
Member、Boolean与Version Names(…
典型失效
若把「Member、Boolean与Version Names(…」当作脱离版本与上下文的硬规则,可能用过时的优化或风格替换了更重要的正确性、安全性与可维护性约束。
核验证据
固定当前 .NET、语言版本和输入规模,用编译诊断、分析器、自动化测试、基准或安全失败样本复核「Member、Boolean与Version Names(…」的收益与反例。
为什么命名规范是一套Search和Compatibility系统
好名字让reader不打开implementation也能预测type角色、boolean真值、event时机和module owner;一致casing让IDE、analyzer与API docs形成统一索引。命名并非追求最长描述,而是在作用域内消除歧义,并给未来新增type/version留下空间。
先预测:所有enum type都应该用复数吗;assembly是否必须与root namespace一一对应;NotDisabled是否比IsEnabled更精确。答案都是否。规则必须结合semantic scope、artifact boundary和call-site readability。
Namespace、Type与Generic Names(建议122-130)
建议122:以.为命名空间命名
dot分隔稳定层级,例如Company.Product.Domain.Feature;每段使用PascalCase并代表真实ownership/概念,不机械映射每个folder。层级太深增加using与移动成本,Common.Helpers.Utils则几乎没有semantic signal。
namespace Contoso.Billing.Invoicing;
public sealed class Invoice { }建议123:程序集不必与命名空间同名
assembly是build/deployment/version boundary,namespace是source/API organization;一个cohesive assembly可承载多个相关namespaces,一个namespace也可能跨contracts与implementation assemblies。名字应各自表达artifact responsibility,并由dependency rule防止cycle。
建议124:考虑在命名空间中使用复数
namespace segment按自然domain vocabulary选择,例如.Collections、.Diagnostics常为复数,.Security、.Billing则不是。不要强制所有segments复数;关键是整个codebase一致、读起来像分类,并避免namespace与type同名造成qualification confusion。
建议125:避免用FCL的类型名称命名自己的类型
自定义Task、File、String、Timer或Exception会与System/FCL概念冲突,使using、docs和code review误判semantics。用domain noun说明区别,如ImportJob、StoredDocument、BillingClock。
建议126:用名词和名词组给类型命名
class/struct/record表示entity、value、service或concept,使用noun/noun phrase,如Invoice, Money, RetryPolicy。避免DoPayment这类method-shaped type,也避免Manager、Processor没有宾语/职责的宽泛尾缀。
建议127:用形容词组给接口命名
原题适用于capability interface,如IComparable、IFormattable;role/service接口也可用noun phrase,如IInvoiceReader。统一使用I前缀,名字描述caller依赖的role/capability,不暴露Default/Sql等implementation。
建议128:考虑让派生类的名字以基类名字作为后缀
当hierarchy是public vocabulary且suffix能说明substitution时可用,如ArgumentException、FileStream;不应机械产生SqlInvoiceRepositoryBaseRepository。名字先表达derived的semantic distinction,再决定是否保留base role suffix。
建议129:泛型类型参数要以T作为前缀
单一明显参数用T,多个参数用TKey、TValue、TResult等T+role,明确每个type argument位置。不要用T1/T2或与具体class同名;constraint仍需承担capability说明。
public interface IMapper<in TSource, out TResult>
{
TResult Map(TSource source);
}建议130:以复数命名枚举类型,以单数命名枚举元素
现代.NET规则要加条件:普通enum一次表示一个value,type用单数OrderStatus;只有[Flags]可组合bit set时type通常用复数FilePermissions。members保持单数PascalCase,并提供0值None/Unknown语义。
public enum OrderStatus { Unknown = 0, Pending, Paid }
[Flags]
public enum FilePermissions { None = 0, Read = 1, Write = 2 }切换namespace、assembly、FCL collision、interface与enum
Member、Boolean与Version Names(建议131-136)
建议131:用PascalCasing命名公开元素
public/protected types、methods、properties、events使用PascalCase,与.NET ecosystem一致;acronym按项目/FCL style处理,例如HttpClient而非HTTPClient。用formatter/analyzer自动执行,不靠review争论大小写。
建议132:考虑用类名作为属性名
当property自然表示某type的主要value时,同名可读,如public Color Color { get; };若call site含糊,使用semantic role如BackgroundColor、CurrentState。不要为避免重名制造ColorValue等无意义suffix。
建议133:用camelCasing命名私有字段和局部变量
locals/parameters用camelCase;private fields现代C#项目常用_camelCase以区分成员,具体以.editorconfig为source of truth。名字表达meaning/lifetime,不用strName、iCount等Hungarian type prefix。
private readonly IInvoiceStore _invoiceStore;
public Task<Invoice?> FindAsync(InvoiceId invoiceId, CancellationToken cancellationToken)
=> _invoiceStore.FindAsync(invoiceId, cancellationToken);建议134:有条件地使用前缀
保留生态有强signal的前缀:interface的I、generic parameter的T;避免成员scope/mutability/type编码前缀,如m_, s_, str, obj,除非legacy interop/generated convention要求。analyzer一致性优先于个人风格。
建议135:考虑使用肯定性的短语命名布尔属性
boolean以true时的positive predicate命名:IsEnabled, CanRetry, HasItems, ShouldFlush。避免NotDisabled、NoErrors与double-negative condition;若值是三态unknown/yes/no,就不要用bool强行表达。
if (job.IsEnabled && job.CanRetry)
await RetryAsync(job, cancellationToken);建议136:优先使用后缀表示已有类型的新版本
需要短期并存wire/API versions时可用ProtocolV2、ParserV2后缀,比NewParser稳定;但implementation差异能语义命名时优先StreamingParser、Utf8Parser。version suffix必须绑定migration/deprecation plan,不能永久累积V2/V3/VNext。
切换public/private、property、boolean与version names
Delegate、Event与Handler Names(建议137-139)
建议137:委托和事件类型应添加上级后缀
自定义event payload用EventArgs后缀,delegate type在确有独立public contract时用Handler、Callback等能说明role的后缀;常见shape优先EventHandler<TEventArgs>、Action/Func,不为每个event重复声明delegate type。
建议138:事件和委托变量使用动词或形容词短语命名
event描述发生/将发生的动作:完成事实用past tense如OrderPaid,可取消前置事件用present participle如OrderPaying;避免OnOrderPaid作为event名,On前缀通常留给publisher raise method。delegate variable按action命名validate, convert, onCompleted。
建议139:事件处理器命名采用组合方式
业务handler可用HandleOrderPaid,publisher protected raiser用OnOrderPaid;WinForms/WPF designer常用SaveButton_Click的source+event组合,适合UI glue。需要unsubscribe时保存named handler或delegate instance,不以匿名lambda导致无法移除。
public event EventHandler<OrderPaidEventArgs>? OrderPaid;
protected virtual void OnOrderPaid(OrderPaidEventArgs args)
=> OrderPaid?.Invoke(this, args);
private void HandleOrderPaid(object? sender, OrderPaidEventArgs args) { }切换EventArgs、cancelable event、delegate role、handler与UI legacy
本章回顾:名字要在Scope内稳定地区分责任
- namespace用dot组织semantic ownership,assembly独立表达deployment/version boundary。
- 避免FCL collision;type用noun,interface用role/capability,generic parameter用T+role。
- 普通enum type单数,Flags enum type复数,members单数且0值有意义。
- public PascalCase,local/parameter camelCase,private field遵循项目editorconfig;prefix只保留I/T等强signal。
- boolean用positive predicate,version优先semantic suffix,数字版本带migration plan。
- event tense表达before/after,EventArgs、OnXxx和HandleXxx组成可搜索链。
练习
问题 1:如何重命名Utils.TaskManager.ProcessDATA(bool notDisabled)?
问题 2:普通enum、Flags enum和rich type的名字有什么不同?
问题 3:一条可取消事件如何命名event、args、raiser和handler?
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- semantic namespace
- collision budget
- role name
- boolean polarity
- event tense
原版目录概念补充核对
以下条目补齐官方目录中容易被示例主线掩盖的概念。它们不重复罗列目录,而是明确每项概念的机制、适用边界和验收证据。
建议123:程序集不必与命名空间同名:机制、边界与证据
- 命名规范(建议122-139)中的建议123:程序集不必与命名空间同名是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议124:考虑在命名空间中使用复数:机制、边界与证据
- 命名规范(建议122-139)中的建议124:考虑在命名空间中使用复数是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议125:避免用FCL的类型名称命名自己的类型:机制、边界与证据
- 命名规范(建议122-139)中的建议125:避免用FCL的类型名称命名自己的类型是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议126:用名词和名词组给类型命名:机制、边界与证据
- 命名规范(建议122-139)中的建议126:用名词和名词组给类型命名是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议127:用形容词组给接口命名:机制、边界与证据
- 命名规范(建议122-139)中的建议127:用形容词组给接口命名是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议128:考虑让派生类的名字以基类名字作为后缀:机制、边界与证据
- 命名规范(建议122-139)中的建议128:考虑让派生类的名字以基类名字作为后缀是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议129:泛型类型参数要以T作为前缀:机制、边界与证据
- 命名规范(建议122-139)中的建议129:泛型类型参数要以T作为前缀涉及类型语义、分配和枚举成本,不能凭代码长度或旧版微优化判断。固定运行时、构建模式和输入规模,用基准、分配统计与多组边界数据比较替代方案,同时验证结果语义一致。
建议130:以复数命名枚举类型,以单数命名枚举元素:机制、边界与证据
- 命名规范(建议122-139)中的建议130:以复数命名枚举类型,以单数命名枚举元素是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议131:用PascalCasing命名公开元素:机制、边界与证据
- 命名规范(建议122-139)中的建议131:用PascalCasing命名公开元素是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议132:考虑用类名作为属性名:机制、边界与证据
- 命名规范(建议122-139)中的建议132:考虑用类名作为属性名是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议133:用camelCasing命名私有字段和局部变量:机制、边界与证据
- 命名规范(建议122-139)中的建议133:用camelCasing命名私有字段和局部变量是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议134:有条件地使用前缀:机制、边界与证据
- 命名规范(建议122-139)中的建议134:有条件地使用前缀是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议135:考虑使用肯定性的短语命名布尔属性:机制、边界与证据
- 命名规范(建议122-139)中的建议135:考虑使用肯定性的短语命名布尔属性是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议136:优先使用后缀表示已有类型的新版本:机制、边界与证据
- 命名规范(建议122-139)中的建议136:优先使用后缀表示已有类型的新版本是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议137:委托和事件类型应添加上级后缀:机制、边界与证据
- 命名规范(建议122-139)中的建议137:委托和事件类型应添加上级后缀是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议138:事件和委托变量使用动词或形容词短语命名:机制、边界与证据
- 命名规范(建议122-139)中的建议138:事件和委托变量使用动词或形容词短语命名是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。
建议139:事件处理器命名采用组合方式:机制、边界与证据
- 命名规范(建议122-139)中的建议139:事件处理器命名采用组合方式是一条需要上下文的工程建议,而不是无条件规则。先声明适用的语言/运行时版本、代码约束与反例,再以编译器诊断、分析器、自动化测试或基准结果证明采用该建议确实改善正确性、可维护性或性能。