【问题标题】:Why there is a change in cyclomatic complexity when rearranging switch statements with other dependent factors?为什么在重新排列带有其他相关因素的 switch 语句时,圈复杂度会发生变化?
【发布时间】:2023-12-10 08:26:01
【问题描述】:

以下方法的 CC 将生成为 9

    Public Enum Fruits
        Apple
        Pineapple
        Banana
        PassionFruit
        Orange
        Melon
        Grape
        Mango
    End Enum


  Private Function Fruity(ByVal fruitType As Fruits)

        Select Case fruitType
            Case Fruits.Orange, Fruits.Banana
            Case Fruits.Melon
            Case Fruits.Mango
            Case Fruits.Pineapple
            Case Fruits.Passionfruit
            Case Fruits.Melon, Fruits.Apple
        End Select
    End Function

但当枚举成员值是用户定义时,Fruity 方法的 CC 增加到 14。

 Public Enum Fruits
        Apple = 1
        Pineapple = 3
        Banana = 4
        Passionfruit = 5
        Orange = 7
        Melon = 9
        Grape = 11
        Mango = 13
    End Enum

现在假设我将 select-case 语句更改如下,然后方法 Fruity 的 CC 更改为 7,但与上述 select-case 相比,可维护性指数略有下降。

 Select Case true
       Case fruitType= Fruits.Orange or fruitType= Fruits.Banana
       Case fruitType=Fruits.Melon
       Case fruitType=Fruits.Mango
       Case fruitType=Fruits.Pineapple
       Case fruitType=Fruits.Passionfruit
       Case fruitType=Fruits.Melon, Fruits.Apple
  End Select

在最后一个场景中,我将参数的数据类型更改为整数并访问一个名为蔬菜的不同枚举,其值为 50。现在,Fruity 方法的 CC 飙升至 52。但如果我将 Potato 的值更改为0 或 1 然后 CC 保持在 15。

  Public Enum Vegetables
   Potato = 50
  End Enum

  Private Function Fruity(ByVal fruitType As Integer)

        Select Case fruitType
            Case Fruits.Orange, Fruits.Banana
            Case Fruits.Melon
            Case Fruits.Mango
            Case Vegetables.Potato
            Case Fruits.Passionfruit
            Case Fruits.Melon, Fruits.Apple
        End Select
    End Function

这些都在 VS 2008 Team 系统版 3.5SP1 中进行了测试。我想知道这4种情况下CC为什么会有波动。

它与下面给出的第二点有关吗?因为如果我在第 4 种情况下删除掉线案例,CC 确实会下降到 9。那么这是 VS 2008 中的错误吗?

Visual Studio 2010 特别说明

使用 Visual Studio 2010 计算代码指标时可能存在不适用于 Visual Studio 2008 的差异。在线文档 (http://msdn.microsoft.com/en-us/library/ee703787.aspx) 给出了以下原因:

  1. 该函数包含一个或多个 catch 块。在 Visual Studio 的早期版本中,catch 块不包括在计算中。在 Visual Studio 2010 中,每个 catch 块的复杂性都被添加到函数的复杂性中。

  2. 该函数包含一个 switch(VB 中的 Select Case)语句。 Visual Studio 2010 和更早版本之间的编译器差异可能会为某些包含失败案例的 switch 语句生成不同的 MSIL 代码。

【问题讨论】:

    标签: vb.net .net-3.5 code-metrics cyclomatic-complexity select-case


    【解决方案1】:

    圈复杂度计数是一个相当简单的功能,它只计算从您的代码生成的 IL 中出现的分支数。每个分支将计数增加 1。

    您需要查看该 IL,从 Visual Studio 命令提示符运行 ildasm.exe utility。当您比较这些不同 sn-ps 的 IL 时,就会立即明白为什么复杂度会发生这样的变化。

    • 您的第一个版本生成一个Opcodes.Switch,每个枚举都有一个条目。 switch 表中的每个条目都对应一个 Case 语句,并将复杂度计数增加 1
    • 您的下一个版本增加开关表的大小。它为缺少的枚举值添加条目。这不恰当地增加了复杂性计数,该工具不够智能,无法识别虚拟条目,并且无法轻松做到这一点
    • 您的上一个版本的枚举值有太多空白。编译器识别出 Opcodes.Switch 不再有效并生成完全不同的代码,现在使用一系列 If/ElseIf 测试。降低复杂度。

    仅使用圈复杂度作为粗略的指导,它还不够复杂,不足以证明进行剧烈的代码更改是合理的。

    【讨论】:

      最近更新 更多