用途:编写惯用、可空且显式的 C# 代码,用类型建模领域,异步不掩盖 I/O。相关技能:Web 用 aspnet-core,持久化用 entity-framework,测试用 csharp-testing。
工具链:新代码用 .NET 10+ SDK;尊重仓库的 TargetFramework / global.json。启用可空引用类型(<Nullable>enable</Nullable>)。使用 dotnet format、dotnet test、analyzers;若 CI 已要求,新代码启用 TreatWarningsAsErrors。仓库已用时采用集中包管理(Directory.Packages.props)。
组织:按边界而非装饰性分层划分项目(如 src/ 下 MyApp、MyApp.Domain、MyApp.Infrastructure,tests/ 下 MyApp.Tests)。默认 internal,仅稳定 API 用 public。使用文件范围命名空间,隐式 using 仅限 SDK 自带。
语言:值类型用 record / record struct,身份与生命周期用 class。类型较薄时用主构造函数。用模式匹配(is、switch 表达式)替代 if + cast。契约对象用 required / init,避免无不变量的公共 setter。集合用 List<T>、IReadOnlyList<T>,不可变且热路径用 FrozenDictionary。LINQ 求清晰,避免 I/O 中 N+1。span/Memory 仅用于经测量的热路径。
可空与错误:显式 T?,不用盲目的 !;仅在本地不变量有注释时使用 null-forgiving。库 API 在 Result<T> 与领域异常间按边界择一。用 ArgumentNullException.ThrowIfNull,在边界校验。不要 catch (Exception) 吞掉异常,保留 InnerException。
异步:async Task/ValueTask 直达边界,不用 .Result / .Wait()。I/O 传 CancellationToken,关闭时取消。库中 ConfigureAwait(false),ASP.NET 应用无需。CPU 密集仅在有必要时用 Task.Run,不要包装同步阻塞。
DI 与配置:按生命周期注册(无状态 Singleton,按请求/UoW 的 Scoped)。用 Options 模式 + IValidateOptions,密钥不入代码。不用服务定位器。
反模式:新 API 用 dynamic / object;async void(UI 事件处理器除外);假定 HttpContext / DbContext;领域用 DateTime.Now(注入时钟);带状态的静态 helper 类。
集成:HTTP 用 aspnet-core,ORM 用 entity-framework,测试用 csharp-testing,实时用 signalr,HTTP 契约用 api-design。
完成标准:范围内可空与警告已处理;I/O 边界异步带 CT;公共 API 最小化,领域用 record/enum;关键路径有测试;无 .Result / 异常吞没。