C# 命名规范

156 阅读5分钟

1. 简介

本文档旨在为 C# (.NET) 项目提供一套清晰的大小写命名指导。本规范主要基于 Microsoft 官方的 .NET 设计准则,并结合了业界广泛认可的最佳实践。

2. 核心命名法

所有命名都应基于以下两种大小写风格:

  • PascalCase (帕斯卡命名法): 每个单词的首字母均大写。

    示例: ProductService, CalculateTotalPrice

  • camelCase (驼峰命名法): 第一个单词首字母小写,后续单词首字母大写。

    示例: productService, calculateTotalPrice

3. 具体命名规则

元素类型命名规范示例备注
类 (Class)PascalCaseProductController, UserService名称应为名词或名词短语。
接口 (Interface)IPascalCaseIProductRepository, ILogger必须以大写字母 I 为前缀。
枚举 (Enum)PascalCaseOrderStatus, PaymentMethod
结构体 (Struct)PascalCasePoint, Color
公共成员 (Public Member)PascalCaseFirstName, GetUserDataAsync()包括属性、方法、事件。异步方法以 Async 结尾。
方法参数 (Parameter)camelCase(int customerId, string userName)
局部变量 (Local Variable)camelCasevar itemCount = 0;
私有/保护字段_camelCase_dbContext, _logger强烈推荐使用下划线 _ 前缀以区分成员字段。
常量 (const, static readonly)PascalCaseMaxPageSize, DefaultConnection注意:这与某些语言的全大写规范不同。

4. 集合与聚合根 (Aggregate) 命名

在处理一组对象或领域驱动设计 (DDD) 中的聚合时,命名同样需要遵循清晰的规则。

  • 普通集合 (Collections):

    规范: 使用复数名词,并遵循其作用域的大小写规则。

    示例:

// 方法内的局部变量
var users = new List<User>();
// 类的公共属性
public IEnumerable<Product> Products { get; set; }
  • 聚合根 (Aggregate Roots):

    规范: 聚合根是领域模型的核心,代表一组相关对象的“根”实体。它应使用来自业务领域的单数名词,并采用 PascalCase。

    示例:

// Order 是聚合根,它内部包含了 OrderItem 的集合
public class Order
{
    public int Id { get; private set; }
    public List<OrderItem> Items { get; private set; } = new();
    public decimal TotalPrice { get; private set; }
    // ... 聚合根包含自身的业务逻辑
    public void AddItem(Product product, int quantity)
    {
        // ... 业务规则检查
    }
}
  • 注意事项:
  1. 名称源于业务: 聚合根的名称应直接反映业务术语(领域通用语言),如“订单(Order)”、“客户(Customer)”、“帖子(Post)”。
  2. 保持单数: 聚合根代表一个独立的业务单元,即使它内部包含集合,其本身也应是单数命名。
  • 避坑指南:

    误区一:将聚合根与数据表混淆。不要为数据库中的每个表都创建一个所谓的“聚合根”。聚合根是一个业务概念,是数据一致性的边界,而不是数据存储的映射。

    误区二:聚合根命名不明确。避免使用 OrderData, OrderModel, OrderEntity 等技术性后缀。直接命名为 Order,其含义应在业务领域中清晰明确。

5. 处理复杂业务与模块化命名

当项目包含多个业务模块,且不同模块可能含有用途相似(如 Request, Response)的类时,必须采用更精确的命名策略以避免混淆。

5.1. 核心原则:使用业务上下文作为前缀/后缀

这是解决模块化命名冲突最直接、最重要的方法。让类名自带上下文信息,从而实现自解释。

规则:[业务实体名][类的用途]

类别示例解释
请求 (Request)CreateUserRequest, UpdateProductRequest用于封装创建用户或更新产品的API请求体数据。
响应 (Response)OrderResponse, AddressValidationResponse用于封装外部API返回的数据。
数据传输对象 (DTO)ProductDto, CustomerDetailsDto用于在程序内部各层之间传输数据,或作为API的最终返回模型。

通过这种方式,OrderResponse 和 AddressResponse 的类名在任何地方都是清晰、无歧义的。

5.2. 结合命名空间进行物理隔离

在遵循核心命名原则的基础上,通过清晰的目录结构和命名空间来组织相关类,可以进一步提升代码的规整性。

示例目录结构:

/Infrastructure
└─── /Clients
     ├── /OrderApiClient/
     │   └── /Models/
     │       ├── CreateOrderRequest.cs
     │       └── OrderResponse.cs          // -> MyProject.Infrastructure.Clients.OrderApiClient.Models
     │
     └─── /AddressApiClient/
         └─── /Models/
             ├── ValidateAddressRequest.cs
             └── AddressResponse.cs        // -> MyProject.Infrastructure.Clients.AddressApiClient.Models

5.3. 高级模式:CQRS 命名法

对于业务逻辑极其复杂的场景,可以引入 CQRS (命令查询责任分离) 模式,它能带来极致的命名清晰度。

查询 (Query): 负责读取数据。

查询请求: GetOrderByIdQuery

查询结果: GetOrderByIdQueryResult

命令 (Command): 负责修改数据。

命令请求: SubmitOrderCommand, CancelOrderCommand

这种命名方式将类的具体意图完整地体现在名称中,消除了任何可能的歧义。

6. Web API JSON 序列化规范

6.1. 自动处理 PascalCase 到 camelCase 的转换

问题: 后端 C# 属性遵循 PascalCase,而前端 JavaScript 事实标准为 camelCase。

原则: 后端 C# 代码应始终保持 PascalCase 规范。

解决方案: 在 API 项目启动时,全局配置 JSON 序列化器,使其自动将 PascalCase 属性转换为 camelCase JSON 字段。

在 ASP.NET Core 项目的 Program.cs 文件中添加以下配置:

// Program.cs
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        // 自动将 C# 的 PascalCase 属性序列化为 JSON 的 camelCase
        options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    });

6.2. 处理特殊的 JSON 命名风格

如果需要与要求特殊命名(如 kebab-case 或 SNAKE_CASE)的第三方系统交互,你有两种方式处理,而无需改变 C# 的命名规范。

方式一:使用 [JsonPropertyName] 特性(推荐) 这是最简单直接的方式,可以针对特定属性覆盖全局策略。

using System.Text.Json.Serialization;

public class LegacySystemDto
{
    // 将 C# 的 PascalCase 属性映射到 JSON 的 kebab-case (横杠连接)
    [JsonPropertyName("user-id")]
    public int UserId { get; set; }

    // 将 C# 的 PascalCase 属性映射到 JSON 的 SNAKE_UPPER_CASE (全大写蛇形)
    [JsonPropertyName("API_KEY")]
    public string ApiKey { get; set; }

    // 全局策略仍然生效,此属性会被序列化为 "normalProperty"
    public string NormalProperty { get; set; }
}

方式二:创建自定义命名策略(高级) 如果整个 API 都需要遵循一种非标准的命名风格(例如,整个项目都需要输出蛇形命名 snake_case),你可以创建自己的命名策略。

// 1. 创建自定义策略类
public class SnakeCaseNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name)
    {
        // 一个将 PascalCase 转换为 snake_case 的简单实现
        return string.Concat(name.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString())).ToLower();
    }
}

// 2. 在 Program.cs 中注册它
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        // 使用你的自定义策略
        options.JsonSerializerOptions.PropertyNamingPolicy = new SnakeCaseNamingPolicy();
    });

7. 官方参考资料

.NET 命名准则: docs.microsoft.com/zh-cn/dotne…