mcpField
C
csharp

csharp

github.com/alexander-danilenko开发1879 次安装2 周前更新
代码仓库

关于 csharp

csharp 是编写和修改 C# 12 / .NET 8+ 代码的团队规范,面向开发者,涵盖语言模式、异步与取消、数据访问、依赖注入和配置。

主要功能

  1. 01将可空警告视为错误
  2. 02C# 12 语言规范
  3. 03预期失败的 Result 模式
  4. 04异步方法传递取消令牌
  5. 05EF Core 查询与更新实践
  6. 06经过验证的选项和 HTTP 客户端模式

适用场景

  1. 01规范新编写的 C# 代码
  2. 02审查 .NET 8+ 项目变更
  3. 03指导 EF Core 查询实现

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/alexander-danilenko/cortex-ai-skills --skill csharp

安装后在 Claude Code 中输入/csharp确认已加载。

详细介绍

C# 约定

C# 12 / .NET 8+ 的项目约定。对你编写或修改的代码应用这些约定——除非有人要求,否则不要重写未改动的文件来符合这些约定。

约定

  • <Nullable>enable</Nullable> 并将警告视为错误。 只有在警告会阻止构建时,可空注解才有用;忽略警告后,它们就成了装饰,让人误以为哪些引用可以为 null。

  • C# 12 默认做法: 文件范围的命名空间、主构造函数、集合表达式、required 成员。DTO 和值对象使用记录类型——比较数据时需要的是值相等性,而手写的 Equals/GetHashCode 往往会逐渐不一致。

  • 优先使用模式匹配,而非类型测试后再强制转换的链式写法。 对封闭层次结构使用 switch 表达式,编译器可以警告未处理的情况;而 if/else if 链在出现新类型时只会静默跳过。

  • 预期内的失败使用 Result 模式,真正异常的情况使用异常。 “未找到”和“输入无效”都是常见结果,应体现在返回类型中,以便调用方必须处理;用异常控制流程会让方法签名无法体现这些情况,并且每次发生都要进行一次堆栈展开。封闭的记录类型层次结构可以对各种结果进行穷尽式 switch:

    public abstract record Result<T>
    {
        public sealed record Ok(T Value) : Result<T>;
        public sealed record Fail(string Error) : Result<T>;
    }
    
    var message = GetUser(id) switch
    {
        Result<User>.Ok(var user) => $"Found {user.Name}",
        Result<User>.Fail(var error) => error,
    };
    
  • 异步一路贯穿到底。 .Result 和 .Wait() 会在同步上下文中导致死锁,在其他情况下则会占用线程池线程。如果调用链底层必须是异步的,那么顶层也必须是异步的。

  • 每个异步公共方法都要接受并传递 CancellationToken。 否则,请求取消后,数据库查询和 HTTP 调用仍会继续运行至完成,而已经离开的调用方仍要承担这部分开销。

  • 绝不通过 API 暴露 EF 实体。 使用 Select 投影到 DTO——否则你会把未来新增到架构中的字段一并发送出去,而延迟加载还会让序列化引发 N+1 查询风暴。

  • 这些 EF 特性引发的是生产事故,而非测试失败: 对每个只读查询使用 AsNoTracking(),因为在大型结果集上进行更改跟踪纯属额外开销;Include 多个集合时使用 AsSplitQuery(),因为单次联接会以笛卡尔方式成倍增加行数;进行批量更改时使用 ExecuteUpdateAsync/ExecuteDeleteAsync(.NET 7+),而不是加载实体后再修改;使用全局 HasQueryFilter 处理软删除,避免任何查询遗漏标记。

  • 当一个接口有多个实现时使用键控服务(.NET 8):使用 AddKeyedScoped<INotifier, EmailNotifier>("email") 注册,并通过 [FromKeyedServices("email")] 解析。它优于使用枚举切换的工厂,因为生命周期仍由容器管理。

  • 使用经过验证的强类型配置和 IOptions<T>。 configuration["Some:Key"] 会在调用处因拼写错误而于运行时失败。绑定选项类并使用 ValidateOnStart,则会在启动时失败,并指出具体字段。

  • 使用 IHttpClientFactory,绝不要每次调用都 new HttpClient()——滞留的 TIME_WAIT 连接导致套接字耗尽是经典故障,而且只会在高负载时显现。

  • 只有在性能分析器显示分配开销确实重要时,才使用 Span<T>/Memory<T> 和对象池。 它们会让代码变复杂,因此应在有测量依据时才承担这份复杂性,而不是出于原则。

评论

支持 Markdown