# 代码约定 **分析日期:** 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*