shennyL
shennyL

Reputation: 2794

Full lists of expression for C# code which +1 for Cyclomatic Complexity

I need to construct a Control Flow Diagram (simple flow graph with nodes and edges) for each method in my C# project in order to demonstrate the graph-way to calculate cyclomatic complexity.

I first counted the cyclomatic complexity using VS 2010, then I construct the graph to make sure the result value is same as the one counted from VS. However, I met some problem here because I not sure which expression is actually consider a +1 for cyclomatic complexity.

Let's look at one example here:

 public ActionResult Edit(string id, string value)
    {
        string elementId = id;
        // Use to get first 4 characters of the id to indicate which category the element belongs
        string fieldToEdit = elementId.Substring(0, 4);

        // Take everything AFTER the 1st 4 characters, this will be the ID
        int idToEdit = Convert.ToInt32(elementId.Remove(0, 4));

        // The value to be return is simply a string:
        string newValue = value;

        var food = dbEntities.FOODs.Single(i => i.FoodID == idToEdit);

        // Use switch to perform different action according to different field
        switch (fieldToEdit)
        {
            case "name": food.FoodName = newValue; break;
            case "amnt": food.FoodAmount = Convert.ToInt32(newValue); break;
            case "unit": food.FoodUnitID = Convert.ToInt32(newValue); break;
            // ** DateTime format need to be modified in both view and plugin script
            case "sdat": food.StorageDate = Convert.ToDateTime(newValue); break;
            case "edat": food.ExpiryDate = Convert.ToDateTime(newValue); break;
            case "type": food.FoodTypeID = Convert.ToInt32(newValue); break;

            default: throw new Exception("invalid fieldToEdit passed");

        }
        dbEntities.SaveChanges();
        return Content(newValue);
    }

For this method, VS calculated the cyclomatic complexity as 10. However, there are only 7 case statement, I don't understand what other expressions contribute to the complexity.

I had search through many sources, but could not get a complete lists of all expressions which will be counted.

Can anyone help on this? Or there is any tool which i can generate Control Flow Diagram from C# code?

Thank you in advance...

Upvotes: 3

Views: 556

Answers (1)

Huske
Huske

Reputation: 9296

What you should do first is try and visualize cyclomatic complexity using graphs. While going through you code I managed to calculate 10. In order to better understand this look at the following:

public void MyMethod()
{
    Console.WriteLine("Hello ShennyL");
}

This has cyclomatic complexity of 1, because there is only one possible path here, and that is to display the message.

public void AnotherMethod()
{
    if (someCondition)
    {
        Console.WriteLine("Hello Shennly");
    }
}

This time we have cyclomatic complexity of 2. +1 is added to if, while, for, foreach. In this case there are two paths. If someCondition is true the message will be displayed (first possible path), and if someCondition is false the message will not be displayed (second possible path).

If you have a look at the implementation of Dispose in Windows Forms it looks like this:

protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
}

Here you have cyclomatic complexity of 3. In case of && both values must be true in order to evaluate the expression inside. That means that if both disposing is true and (components != null) is true you have the first path. If disposing is false you have second path. The third path comes from the fact that components can be null and as such it would evaluate to false. Therefore you have cyclomatic complexity of three.

In case of switch you get +1, and for each case (and default) that appears inside you get +1. In case of your method, you have six case statements and one default plus switch, making this 8 in total.

As I said in the beginning, if you try and visualize you code in terms of graph it can be broken down like this (I am adding my comments to your code and removing your comments):

public ActionResult Edit(string id, string value)                   
{                   
    string elementId = id; // First path, cyclomatic complexity is 1

    string fieldToEdit = elementId.Substring(0, 4); // Same path, CC still 1  

    int idToEdit = Convert.ToInt32(elementId.Remove(0, 4)); // Same path, CC still 1

    string newValue = value; // Same path, CC still 1

    var food = dbEntities.FOODs.Single(i => i.FoodID == idToEdit); // Boolean expression inside your lambda. The result can go either way, so CC is 2.

    switch (fieldToEdit) // Switch found, so CC is 3
    {                   
        case "name": food.FoodName = newValue; break; // First case - CC is 4
        case "amnt": food.FoodAmount = Convert.ToInt32(newValue); break; // Second case - CC is 5
        case "unit": food.FoodUnitID = Convert.ToInt32(newValue); break; // Third case - CC is 6
        case "sdat": food.StorageDate = Convert.ToDateTime(newValue); break; // Fourth case - CC is 7
        case "edat": food.ExpiryDate = Convert.ToDateTime(newValue); break; // Fifth case - CC is 8
        case "type": food.FoodTypeID = Convert.ToInt32(newValue); break; // Sixth case - CC is 9

        default: throw new Exception("invalid fieldToEdit passed"); // Defaul found - CC is 10

    }                   
    dbEntities.SaveChanges(); // This belongs to the first path, so CC is not incremented here.                   
    return Content(newValue);                   
}        

I might be wrong in a few points, but basically this is the idea behind the calculation of cyclomatic complexity. You should also understand that there are cases when you cannot decrease this (if you need to use switch/case, the CC increases). Additionally, if your variables have awful naming (as if you tried to obfuscate your code) cyclomatic complexity might return lower value because it cannot understand that you naming is awful. Naming can increase a complexity for you and if you don't use comments in your code, after 6 months you will have hard time figuring why cyclomatic complexity is 3 but you just cannot understand a things that is being written.

Upvotes: 3

Related Questions