圈复杂度 (CC) 是一种代码指标,通过计算线性独立执行路径的数量来衡量方法的结构复杂度。该指标源于图论,它将方法表示为一个控制流图,其中节点是语句块,边是它们之间的跳转。在实际的 C# 开发中,这通常计算为 1 加上方法体内的分支结构数量。这包括 `if`、`while`、`for`、`foreach`、`case`、`default`、`continue` 和 `goto` 等关键字,以及 `&&` 和 `||` 等逻辑运算符,还有 `?:` 和 `??` 等三元运算符。

由于 CC 代表独立路径的数量,它可作为可测试性的直接代理。高 CC 分数的方法本质上更难阅读、测试和安全修改,因为它需要更多的测试用例来确保覆盖每一个可能的分支。虽然没有通用的“完美”分数,但行业标准提供了常见的基准:Thomas McCabe 最初建议限制为 10,而 Microsoft 的 CA1502 分析器会将超过 25 的分数标记为过高。监控此指标的目标是识别“缺陷磁铁”——即那些由于逻辑纠缠,导致单个回归错误极易进入生产环境的复杂方法。

显示 C# 中圈复杂度与代码覆盖率之间关系的图表
可视化圈复杂度如何与 C# 项目所需的代码覆盖率相关联。blog.ndepend.com

文章解释了 CC 如何作为可测试性的直接代理,因为更高的复杂度分数需要更多的测试用例来确保全路径覆盖。

管理高复杂度通常涉及将单个大型方法重构为几个更小、更专注的方法。例如,一个 CC 为 8 的方法可以分解为处理特定任务(如验证或折扣逻辑)的子方法。虽然这种重构可能会略微增加整个代码库的复杂度总和,但它通过确保任何单个代码单元都保持足够简单,以便开发人员一次性理清逻辑,从而提高了可维护性。为了在大规模范围内管理这一点,开发人员可以使用 NDepend 或 Visual Studio 的“计算代码指标”等工具来识别热点。在矩形树图中可视化这些分数——其中矩形的大小代表语句数量,颜色代表 CC 分数——可以让团队快速发现需要架构关注的大型、高复杂度方法。

C# 圈复杂度分数的矩形树图可视化
一个矩形树图可视化,其中矩形大小代表语句计数,颜色表示圈复杂度分数。blog.ndepend.com

文中描述了使用矩形树图来可视化分数,其中大小代表语句数量,颜色代表 CC 分数,以识别热点。

然而,圈复杂度在现代面向对象编程中存在显著的局限性。由于该指标侧重于显式分支,它并未考虑到多态性引入的隐式复杂度。例如,在接口上调用虚方法可能会根据底层实现导致数十种不同的执行路径,但这样做并不会增加 CC 分数。因此,虽然 CC 是识别复杂过程逻辑的极佳工具,但它应与嵌套深度和测试覆盖率等其他指标结合使用,以提供系统可维护性的完整图景。