mcpField
D
dotnet-csharp-code-smells

dotnet-csharp-code-smells

github.com/wshaddix测试与质量86169 次安装35 周前更新
代码仓库

关于 dotnet-csharp-code-smells

为 C# 开发者和代码审查者提供代码异味与反模式检查指南。内容按资源管理、LINQ、事件处理和设计等领域分类,并列出危害、修正方向及相关 CA 规则。

主要功能

  1. 01识别资源释放问题
  2. 02检查 LINQ 反模式
  3. 03发现事件处理泄漏
  4. 04整理异常处理缺陷
  5. 05关联 CA 代码分析规则

适用场景

  1. 01审查 C# 代码中的常见异味
  2. 02排查资源泄漏和事件订阅问题
  3. 03依据 CA 规则改进代码质量

安装

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

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-csharp-code-smells

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

附带文件details.md

详细介绍

dotnet-csharp-code-smells

主动检测 C# 代码中的代码异味和反模式。此技能会在所有工作流模式(规划、实现和审查)中触发。每个条目都会指出代码异味、说明其危害、给出正确的修复方式,并引用相关的 CA 规则或交叉参考。

交叉参考:[skill:dotnet-csharp-async-patterns],了解异步相关陷阱;[skill:dotnet-csharp-coding-standards],了解命名和风格;[skill:dotnet-csharp-dependency-injection],了解 DI 生命周期误用;[skill:dotnet-csharp-nullable-reference-types],了解 NRT 注解错误。

不在本技能范围内: LLM 特有的生成错误(错误的 NuGet 包、不佳的项目结构、MSBuild 错误)由 [skill:dotnet-agent-gotchas] 介绍。本技能介绍的是所有开发者(无论是人类还是 AI)都应避免的一般 .NET 代码异味。


1. 资源管理(误用 IDisposable)

代码异味危害修复方法规则
可释放的局部变量缺少 using泄漏非托管句柄(套接字、文件、数据库连接)使用 using 声明或 using 代码块CA2000
IDisposable 字段未释放类持有可释放资源,却从不释放实现 IDisposable;在 Dispose() 中释放字段CA2213
Dispose 模式错误(没有终结器保护)重复释放,或在 GC 终结时遗漏清理遵循标准的 Dispose(bool) 模式;调用 GC.SuppressFinalize(this)CA1816
在一个方法中创建可释放对象,并存入字段所有权不明确;容易忘记释放记录所有权;使包含该字段的类实现 IDisposableCA2000
对非自有资源使用 using过早释放共享资源(例如,注入的 HttpClient)只释放自己创建的资源;让 DI 管理注入的服务--

有关每种模式的代码示例,请参阅 details.md。


2. 警告抑制技巧

代码异味危害修复方法规则
通过以 null 调用事件来抑制 CS0067造成误导性的运行时行为;掩盖真正的错误使用 #pragma warning disable CS0067 或显式事件访问器 { add {} remove {} }CS0067
通过虚设变量赋值来抑制 CS0219死代码会让读者困惑使用 _ = expression; 丢弃值,或使用 #pragma warning disableCS0219
使用 #pragma warning disable 后未恢复会抑制文件其余部分的所有警告始终配对使用 #pragma warning restore;只抑制特定代码--
使用 [SuppressMessage] 时未提供理由后续维护者无法判断抑制是否仍然有效始终包含 Justification = "reason"CA1303

有关 CS0067 的示例(从错误模式改为正确修复),请参阅 details.md。


3. LINQ 反模式

代码异味危害修复方法规则
链式调用中途过早使用 .ToList()强制完全物化;浪费内存保持链式调用为延迟执行;只在末尾物化CA1851
多次枚举 IEnumerable<T>每次枚举都会重新执行查询或数据库调用使用 .ToList() 物化一次,然后重复使用CA1851
在 EF Core 中进行客户端求值将整张表加载到内存;造成隐蔽的性能问题将查询改写为可转换的 LINQ,或明确表达意图后使用 AsAsyncEnumerable()--
使用 .Count() > 0 而不是 .Any()会枚举整个集合,而不是短路求值检查是否存在元素时使用 .Any()CA1827
使用嵌套 foreach,而不是 .Join() 或 .GroupJoin()本可达到 O(n+m),却变成 O(n*m)使用 LINQ join 操作或 Dictionary 查找--
使用 .Where().First(),而不是 .First(predicate)创建不必要的中间迭代器将谓词直接传递给 .First() 或 .FirstOrDefault()CA1826

4. 事件处理泄漏

异味危害修复方法规则
未取消订阅事件内存泄漏:发布者持有订阅者的引用在 Dispose() 中取消订阅,或使用弱事件模式--
在构造函数中引发事件订阅者可能尚未连接;派生类也尚未完全构造仅从完全初始化的实例引发事件CA2214
误用 async void 事件处理程序async void 是事件处理程序唯一有效的签名,但异常无法观测在主体中使用 try/catch;明确记录并处理异常--
事件处理程序未检查 null没有订阅者时会发生 NullReferenceException使用 event?.Invoke() 空条件模式--
静态事件未清理根引用会阻止对象在应用程序生命周期内被 GC 回收优先使用实例事件,或使用 WeakEventManager--

交叉引用:[skill:dotnet-csharp-async-patterns] 深入介绍了 async void 即发即弃模式。


5. 设计异味

异味阈值危害修复方法
上帝类>500 行职责过多;难以测试和维护运用 SRP 提取内聚的类
过长方法>30 行难以理解、测试和审查提取名称明确的辅助方法
参数列表过长>5 个参数表明缺少抽象引入参数对象或构建器
特性嫉妒方法使用其他类的数据多于自身数据职责错位;耦合紧密将方法移至其所嫉妒的类中
基本类型偏执用原始 string/int 表示领域概念缺少类型安全;验证逻辑分散引入值对象或强类型 ID
嵌套过深>3 层缩进控制流难以跟踪使用守卫子句(提前返回)并提取方法

6. 异常处理缺漏

异味危害修复方法规则
空 catch 块静默吞掉错误;掩盖 bug至少记录异常;优先让异常继续传播CA1031
捕获基类 Exception会捕获 OutOfMemoryException、StackOverflowException 等捕获特定异常类型CA1031
记录后吞掉(catch { log; })调用方无法得知操作失败记录后重新抛出,或返回错误结果--
在 finally 中抛出异常新异常会掩盖原始异常在 finally 内使用 try/catch;绝不从 finally 中抛出异常--
使用 throw ex; 而非 throw;重置堆栈跟踪;隐藏原始故障位置使用裸 throw; 保留堆栈跟踪CA2200
未包含内部异常包装异常时会丢失因果链将原始异常作为 innerException 参数传入--

交叉引用:[skill:dotnet-csharp-async-patterns] 介绍了即发即弃和 async void 场景中的异常处理。


快速参考:CA 规则

规则说明
CA1031不要捕获一般异常类型
CA1816正确调用 GC.SuppressFinalize
CA1826不要对可按索引访问的集合使用 Enumerable 方法
CA1827可使用 Any() 时,不要使用 Count()/LongCount()
CA1851可能多次枚举 IEnumerable 集合
CA2000在对象超出作用域前将其释放
CA2200重新抛出异常以保留堆栈详细信息
CA2213应释放可释放字段
CA2214不要在构造函数中调用可重写的方法

在项目中通过 <AnalysisLevel>latest-all</AnalysisLevel> 启用这些规则。分析器配置请参阅 [skill:dotnet-csharp-coding-standards]。


参考资料

评论

支持 Markdown