我需要为我的 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 个 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 为真,将显示消息(第一个可能的路径),如果 someCondition 为假,则不会显示消息(第二个可能的路径)。
如果您查看 Windows 窗体中 Dispose 的实现,它看起来像这样:
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
此处的圈复杂度为 3。在 && 的情况下,两个值都必须为真才能计算内部表达式。这意味着如果 both disposing
是真的 and (components != null)
是真的你有第一条路.如果 disposing
为 false,则您有第二条路径。第三条路径来自 components
可以为 null 的事实,因此它会评估为 false。因此,您的圈复杂度为三。
在 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);
}
我可能有几点错了,但这基本上就是圈复杂度计算背后的思想。你还应该明白,有些情况下你不能减少它(如果你需要使用 switch/case,CC 会增加)。此外,如果您的变量命名很糟糕(就像您试图混淆代码一样),圈复杂度可能会返回较低的值,因为它无法理解您的命名很糟糕。命名会增加您的复杂性,如果您不在代码中使用注释,6 个月后您将很难弄清楚为什么圈复杂度为 3,但您就是无法理解正在编写的内容。
关于c# - C# 代码的完整表达式列表,其中圈复杂度为 +1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8379644/