4

I have two sample functions TestComplexityIf and TestComplexitySwitch. VisualStudio-2017 'Calculate Code Metrics' tool reports a cyclomatic complexity of 10 for the function with switch statement ad 7 for the one with if-else. I wonder how the complexity for TestComplexitySwitch() is calculated.

private static void TestComplexityIf(String arg)
{
    if (arg == "a")
    { }
    else if (arg == "b")
    { }
    else if (arg == "c")
    { }
    else if (arg == "d")
    { }
    else if (arg == "d")
    { }
    else if (arg == "f")
    { }
    else if (arg == "g")
    { }
}

private static void TestComplexitySwitch(String arg)
{
    switch (arg)
    {
        case "a":
            break;
        case "b":
            break;
        case "c":
            break;
        case "d":
            break;
        case "e":
            break;
        case "f":
            break;
        case "g":
            break;
    }
}

Also, if I comment the last case, complexity suddenly changes to 6.

private static void TestComplexitySwitch(String arg)
{
    switch (arg)
    {
        case "a":
            break;
        case "b":
            break;
        case "c":
            break;
        case "d":
            break;
        case "e":
            break;
        case "f":
            break;
        //case "g":
            //break;
    }
}
FaisalM
  • 724
  • 5
  • 18
  • Have you tried adding a default case? I'm interested in what that should do to the complexity. – Fabian Claasen Mar 18 '20 at 07:34
  • Indentation depth plays into this value, which is higher for the `switch`. Could be as easy as that. – Markus Deibel Mar 18 '20 at 07:43
  • 3
    [sharp io test](https://sharplab.io/#v2:D4AQTAjAsAUCDMACciDCiDetE8QBwCcBLANwEMAXAU2QgDZkAWRAFSoGcLUB7AWzwA2VAB5EKATwCSAMwAUAZQrEAdgHNEZAqoCUsLDFyIi0xLM3qAvBcQAiMjd0HcGRAF9suKgPY1jp84hWtgBGDh44Lu5OOF4+RiZmWoHWNgDGYdGYbuGIsb4JAUE2ACYZhpE5efH+SUWljuXZmVV+iZYp0mXOTYYtBbUpql0RTVE5hKSUNCD0TKwcXHyCImLi8gDuYqkAFgpKRGoaWo76huybFDs1OjmnhripZHF2NgBcOfe4wQRUZADWAG4Pg8njQbKF3plPjhvr9AcCcI9nulIdD7rD/kCoSDnqVUWivj9MQjEEiwVQ3iTDBj4djEaDbJ18QTEDSsWiybYhsyCWyclEooYJuRqLQGCBmGxODx+EJRBINlttmA9ip1OYTjlzkrrg1nCTOS8eWi+XTSQzwZSzdSibSORaUVTCXD2dDDXinTDba7PoaKcboab7c8mZ7Wd6SQB6SOG7lh6NB3ACnIIOYAWVk2kw/NgriAA=) – TheGeneral Mar 18 '20 at 07:47
  • Might be more to do with how its being compiled, count every branch, its closer to the values you describe. Though the last example i count 7 not 6... anyway that was fun while it lasted, who knows... i think you should have bigger things to worry about – TheGeneral Mar 18 '20 at 07:48
  • @Fabian with default case(and all a to g cases) value is 10. – FaisalM Mar 18 '20 at 08:20
  • 1
    Have you tried a less degenerate version of the code, e.g. return a different value from each branch? The current implementation basically does nothing and could be subject to optimizations, as Michael Randall's link illustrates. – Jonas Høgh Mar 18 '20 at 08:31
  • @Michael. It looks like when the number of case statements > 6, .NET uses hash to identify the right `case`. This adds additional '3' more paths. When last `case` is commented, the generated code uses `if` with string comparison instead of hash comparison. – FaisalM Mar 18 '20 at 08:52

1 Answers1

2

The Visual Studio Cyclomatic Complexity (CC) tool calculates values from IL code and thus, is subject to compiler details.

Here you are stumbling on a performance compiler detail: when a switch over a string has strictly more than 6 cases, the compiler creates a hash table for fast string search. This hash table doesn't appear in the C# code but only in the IL code. The IL code becomes more complex to handle this hash table and you get the unexpected CC value. This situation is well illustrated by this link from Michael Randall.

Alternatively you can use the tool NDepend to compute the CC from C# source code, visualize CC values in a colored treemap and run some rules to forbid too complex methods.

Colored Treemap Cyclomatic Complexity

(Disclaimer I work for NDepend)

Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92