Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#代码+;圈复杂度为1_C#_Visual Studio 2010_Cyclomatic Complexity - Fatal编程技术网

C#代码+;圈复杂度为1

C#代码+;圈复杂度为1,c#,visual-studio-2010,cyclomatic-complexity,C#,Visual Studio 2010,Cyclomatic Complexity,我需要为我的C#项目中的每个方法构建一个控制流图(带有节点和边的简单流图),以演示计算圈复杂度的图方法 我首先使用VS 2010来计算圈复杂度,然后构造图以确保结果值与VS计数的值相同。然而,在这里我遇到了一些问题,因为我不确定哪个表达式实际上考虑了圈复杂度的A+1。< / P> 让我们看一个例子: public ActionResult Edit(string id, string value) { string elementId = id; //

我需要为我的C#项目中的每个方法构建一个控制流图(带有节点和边的简单流图),以演示计算圈复杂度的图方法

我首先使用VS 2010来计算圈复杂度,然后构造图以确保结果值与VS计数的值相同。然而,在这里我遇到了一些问题,因为我不确定哪个表达式实际上考虑了圈复杂度的A+1。< / P> 让我们看一个例子:

 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个case语句,我不明白还有哪些表达式导致了复杂性

我搜索了许多来源,但无法获得所有表达式的完整列表

有人能帮忙吗?或者有什么工具可以从C代码生成控制流程图


提前感谢您……

您应该首先尝试使用图形可视化圈复杂度。在检查你的代码时,我设法算出了10。为了更好地理解这一点,请查看以下内容:

public void MyMethod()
{
    Console.WriteLine("Hello ShennyL");
}
这具有圈复杂度1,因为这里只有一条可能的路径,即显示消息

public void AnotherMethod()
{
    if (someCondition)
    {
        Console.WriteLine("Hello Shennly");
    }
}
这一次,圈复杂度为2+1添加到if、while、for、foreach。在这种情况下,有两条路径。如果someCondition为true,则显示消息(第一个可能路径),如果someCondition为false,则不显示消息(第二个可能路径)

如果您查看Windows窗体中Dispose的实现,它看起来如下所示:

protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
}
这里的圈复杂度是3。在&&的情况下,两个值都必须为true才能计算内部的表达式。这意味着,如果两个
都为真并且
(components!=null)
都为真,则您拥有第一条路径。如果
disposing
为false,则有第二条路径。第三条路径来自这样一个事实:
组件
可以为null,因此它的计算结果将为false。因此,圈复杂度为3

如果是
开关
,则获得+1,对于出现在开关内部的每个
案例
(和
默认值
),则获得+1。对于您的方法,您有六条
case
语句和一条
default
加上
switch
,总共8条

正如我在开始时所说的,如果您尝试用图形的形式来可视化代码,它可以像这样分解(我将我的注释添加到您的代码中,并删除您的注释):


我可能在几点上错了,但基本上这就是圈复杂度计算背后的想法。您还应该了解,在某些情况下,您无法降低该值(如果需要使用switch/case,CC会增加)。此外,如果您的变量具有糟糕的命名(就像您试图混淆代码一样),圈复杂度可能会返回较低的值,因为它无法理解您的命名是糟糕的。命名会增加您的复杂性,如果您不在代码中使用注释,6个月后您将很难理解圈复杂度为何为3,但您无法理解正在编写的内容。

对此我没有答案,但我的猜测是,除了开关分支,VS还统计可能引发异常的情况。例如,如果
elementId==null
该方法将在尝试执行第二行时抛出NullReferenceException。这可以被视为一个单独的执行路径。
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);                   
}