Полные списки выражений для кода C#, который +1 для Cyclomatic Complexity

Мне нужно построить управляющую диаграмму потока (простой потоковый граф с узлами и ребрами) для каждого метода в моем проекте C#, чтобы продемонстрировать способ вычисления цикломатической сложности.

Сначала я подсчитал цикломатическую сложность, используя VS 2010, а затем построил график, чтобы убедиться, что значение результата совпадает со значением, подсчитанным из VS. Тем не менее, я столкнулся с некоторой проблемой здесь, потому что я не уверен, какое выражение на самом деле считается +1 для цикломатической сложности.

Давайте посмотрим на один пример здесь:

 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);
    }

Для этого метода VS вычислила цикломатическую сложность как 10. Однако есть только 7 случаев, я не понимаю, какие другие выражения способствуют сложности.

Я провел поиск по многим источникам, но не смог получить полные списки всех выражений, которые будут подсчитаны.

Кто-нибудь может помочь в этом? Или есть какой-либо инструмент, который я могу генерировать схему управления потоком из кода C#?

Заранее спасибо...

1 ответ

Сначала вы должны попытаться визуализировать цикломатическую сложность с помощью графиков. Проходя через ваш код, мне удалось вычислить 10. Чтобы лучше понять это, взгляните на следующее:

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

Это имеет цикломатическую сложность 1, потому что здесь есть только один возможный путь, а именно, чтобы отобразить сообщение.

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

На этот раз мы имеем цикломатическую сложность 2. +1 добавляется к если, в то время как, для, foreach. В этом случае есть два пути. Если someCondition имеет значение true, сообщение будет отображаться (первый возможный путь), а если someCondition имеет значение false, сообщение не будет отображаться (второй возможный путь).

Если вы посмотрите на реализацию Dispose в Windows Forms, она выглядит так:

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

Здесь у вас есть цикломатическая сложность 3. В случае && оба значения должны быть истинными, чтобы оценить выражение внутри. Это означает, что если оба disposing это правда и (components != null) верно, у вас есть первый путь. Если disposing ложно у вас есть второй путь. Третий путь связан с тем, что components может быть нулевым, и как таковой он будет оцениваться как ложный. Поэтому у вас есть цикломатическая сложность три.

В случае switch вы получаете +1, и за каждый case (а также default), который появляется внутри, вы получаете +1. В случае вашего метода у вас есть шесть case заявления и один default плюс switchИтого 8.

Как я уже говорил в начале, если вы попытаетесь визуализировать свой код в виде графика, его можно разбить следующим образом (я добавляю свои комментарии в ваш код и удаляю ваши комментарии):

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);                   
}        

Я могу ошибаться в нескольких моментах, но в основном это идея расчета цикломатической сложности. Вы также должны понимать, что есть случаи, когда вы не можете уменьшить это (если вам нужно использовать переключатель / случай, CC увеличивается). Кроме того, если ваши переменные имеют ужасное наименование (как если бы вы пытались запутать свой код), цикломатическая сложность может возвращать более низкое значение, потому что она не может понять, что ваше именование ужасно. Присвоение имен может усложнить для вас, и если вы не используете комментарии в своем коде, через 6 месяцев вам будет трудно понять, почему цикломатическая сложность равна 3, но вы просто не можете понять, что пишется.

Другие вопросы по тегам