Why there is a change in cyclomatic complexity when rearranging switch statements with other dependent factors?

StackOverflow https://stackoverflow.com/questions/19462829

Вопрос

The CC for the below method would be generated as 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

but when enum member values are user defined then CC of the method Fruity increases to 14.

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

Now let's say I change the select-case statement as below then the CC of the method Fruity changes to 7 but there is slight decline to maintainability index as compared to above 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

In the final scenario, I change the datatype of the parameter to integer and access a different Enum called vegetables which has a value 50. Now the CC of the method Fruity skyrockets to 52. But if i change the value of Potato to 0 or 1 then CC stays at 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

These were all tested in VS 2008 Team system edition with 3.5SP1. I would like to know why there is a fluctuation in the CC in these 4 scenarios.

Does it have something do with the 2nd point given below? Because if i remove the fall through cases in the 4th scenario the CC does drop to 9. So is this a bug in VS 2008?

Special Note on Visual Studio 2010

There may be differences when calculating code metrics using Visual Studio 2010 that don’t apply to Visual Studio 2008. The online documentation (http://msdn.microsoft.com/en-us/library/ee703787.aspx) gives the following reasons:

  1. The function contains one or more catch blocks. In previous versions of Visual Studio, catch blocks were not included in the calculation. In Visual Studio 2010, the complexity of each catch block is added to the complexity of the function.

  2. The function contains a switch (Select Case in VB) statement. Compiler differences between Visual Studio 2010 and earlier versions can generate different MSIL code for some switch statements that contain fall-through cases.

Это было полезно?

Решение

The cyclomatic complexity count is a rather simple feature, it just counts the number of branches that appear inside the IL that's generated from your code. Every branch increases the count by 1.

You'll want to look at that IL, run the ildasm.exe utility from the Visual Studio Command Prompt. When you compare the IL for these different snippets then it will be instantly obvious why the complexity count changes like that.

  • Your first version generates a Opcodes.Switch with one entry for every enum. Each entry in the switch table corresponds with a Case statement and increases the complexity count by 1
  • Your next version increases the size of the switch table. It adds entries for the missing enum values. This inappropriately increases the complexity count, the tool just isn't smart enough to recognize the dummy entries and can't easily do so
  • Your last version has too many gaps in the enum values. The compiler recognizes that an Opcodes.Switch is no longer effective and generates completely different code, now using a train of If/ElseIf tests. Lowering the complexity count.

Only use the cyclomatic complexity as a rough guideline, it just isn't sophisticated enough to justify drastic code changes.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top