# 代码约定
**分析日期:** 2026-02-28
## 命名模式
### 文件
- **类/记录:** PascalCase(如 `ApplicationUser.cs`、`TenantManager.cs`、`TenantInfo.cs`)
- **枚举:** PascalCase(如 `TenantStatus`,定义在 `Tenant.cs` 中)
- **接口:** PascalCase + "I" 前缀(如 `ITenantStore.cs`、`ITenantManager.cs`)
- **配置:** PascalCase + "Configuration" 后缀(如 `TenantConfiguration.cs`)
### 目录
- **聚合文件夹:** PascalCase(如 `UserAggregate/`、`TenantAggregate/`、`RoleAggregate/`)
- **用途文件夹:** PascalCase(如 `Configurations/`、`Migrations/`)
### 命名空间
- **模式:** `Fengling.Platform.{层级}.{聚合}.{组件}`
- **示例:**
- `Fengling.Platform.Domain.AggregatesModel.TenantAggregate`
- `Fengling.Platform.Domain.AggregatesModel.UserAggregate`
- `Fengling.Platform.Infrastructure`
### 类型
| 类型 | 模式 | 示例 |
|------|------|------|
| 类 | PascalCase | `TenantManager`, `PlatformDbContext` |
| 接口 | I + PascalCase | `ITenantManager`, `ITenantStore` |
| 记录 | PascalCase | `TenantInfo` |
| 枚举 | PascalCase | `TenantStatus` |
| 枚举值 | PascalCase | `Active`, `Inactive`, `Frozen` |
| 属性 | PascalCase | `TenantCode`, `CreatedAt`, `IsDeleted` |
| 方法 | PascalCase | `FindByIdAsync`, `GetAllAsync` |
| 参数 | camelCase | `tenantId`, `tenantCode`, `cancellationToken` |
| 私有字段 | camelCase | `_context`, `_tenants` |
## 代码风格
### 项目配置
- **目标框架:** .NET 10.0
- **隐式 using:** 启用
- **可空:** 启用
- **文档生成:** 启用(`true`)
- **集中包管理:** 启用(`true`)
### 格式化
- **大括号:** K&R 风格(开括号在同一行)
- **缩进:** 标准 Visual Studio 默认(4 空格)
- **行尾:** 平台默认(Unix LF,Windows CRLF)
### 全局 Using
Domain 项目 (`Fengling.Platform.Domain/GlobalUsings.cs`):
```csharp
global using NetCorePal.Extensions.Domain;
global using NetCorePal.Extensions.Primitives;
global using System.ComponentModel.DataAnnotations;
```
Infrastructure 项目 (`Fengling.Platform.Infrastructure/GlobalUsings.cs`):
```csharp
global using NetCorePal.Extensions.Domain;
global using NetCorePal.Extensions.Primitives;
global using NetCorePal.Extensions.Repository;
global using NetCorePal.Extensions.Repository.EntityFrameworkCore;
global using MediatR;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.EntityFrameworkCore.Metadata.Builders;
```
## 导入组织
### 顺序
1. 系统命名空间(通过 ImplicitUsings 隐式)
2. 外部包(MediatR、EF Core)
3. 领域命名空间(本地项目)
4. 基础设施命名空间(本地项目)
### 完全限定
- 需要时使用 `Microsoft.AspNetCore.Identity` 的完全限定(如 `ITenantStore.cs` 中的 `Microsoft.AspNetCore.Identity.IdentityResult`)
## 错误处理
### 空检查
**模式:** 显式参数空检查并抛出异常
```csharp
if (modelBuilder is null)
{
throw new ArgumentNullException(nameof(modelBuilder));
}
```
- 位置: `PlatformDbContext.cs` 第 20-23 行
### 空返回
**模式:** 对可空结果返回 `Task.FromResult(null)`
```csharp
if (tenantId == null) return Task.FromResult(null);
```
- 位置: `TenantStore.cs` 第 23 行
### 验证
- 查询中使用 `string.IsNullOrEmpty()` 进行字符串验证
- 对引用类型使用可空注解 `?` 后缀
## 记录类型
### 值对象
**模式:** 带参数的主构造函数记录
```csharp
public record TenantInfo(long? TenantId, string? TenantCode, string? TenantName)
{
public TenantInfo(Tenant? tenant)
: this(tenant?.Id, tenant?.TenantCode, tenant?.Name)
{
}
public static TenantInfo Admin => new TenantInfo(null, null, null);
}
```
- 位置: `TenantInfo.cs`
## 实体设计
### 贫血领域模型
- **Tenant:** 贫血模型(带公共 setter 的数据容器)
- **ApplicationUser:** 富模型,带到 `TenantInfo` 的导航属性
- **ID 类型:** 所有实体标识使用 `long`
### 属性模式
```csharp
public long Id { get; set; }
public string TenantCode { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedAt { get; set; }
public bool IsDeleted { get; set; }
```
## 类设计
### 主构造函数
**模式:** 用于依赖注入的主构造函数
```csharp
public sealed class TenantManager(ITenantStore store) : ITenantManager
{
// 构造函数参数自动成为私有 readonly 字段
}
```
- 位置: `TenantManager.cs` 第 21 行
### 泛型约束
```csharp
public class TenantStore : ITenantStore
where TContext : PlatformDbContext
```
### 方法返回类型
- 异步方法: 返回 `Task` 或 `Task`
- 集合查询: 返回 `IList` 或 `IQueryable`
- 单个实体: 返回 `T?`
## 注释
### 何时注释
- **中文注释:** 用于领域概念和解释
```csharp
///
/// 租户信息
///
public record TenantInfo(...)
```
- **XML 文档:** 用于公共 API
- **最少行内注释:** 仅用于复杂业务逻辑
### JSDoc/TSDoc
- 对公共 API 使用 `/// ` 和 `/// `
- 位置: `TenantInfo.cs` 第 3-8 行、11-13 行
## 函数设计
### 异步方法
- 始终接受 `CancellationToken cancellationToken = default` 作为最后一个参数
- 一致使用 `async`/`await`
- 对有返回值操作返回 `Task`
### 查询方法
- **分页:** 接受 `page` 和 `pageSize` 参数
- **过滤:** 接受可选过滤参数(`name`、`tenantCode`、`status`)
- **排序:** 按创建日期应用 `OrderByDescending`
### IdentityResult 模式
业务操作返回 `IdentityResult`:
```csharp
Task CreateAsync(Tenant tenant, CancellationToken cancellationToken = default);
Task UpdateAsync(Tenant tenant, CancellationToken cancellationToken = default);
Task DeleteAsync(Tenant tenant, CancellationToken cancellationToken = default);
```
## DbContext 设计
### 配置
- **模式:** `OnModelCreating` 中的流式 API
- **实体配置:** 使用 `modelBuilder.Entity(entity => {...})`
- **索引配置:** 使用 `entity.HasIndex(e => e.Property)`
- **拥有类型:** 使用 `entity.OwnsOne(e => e.TenantInfo, navigationBuilder => {...})`
### 配置发现
```csharp
modelBuilder.ApplyConfigurationsFromAssembly(typeof(PlatformDbContext).Assembly);
```
---
*约定分析: 2026-02-28*