c#代码表达式的完整列表,其中圈复杂度为+1
本文关键字:复杂度 列表 代码表 代码 表达式 | 更新日期: 2023-09-27 18:16:58
我需要为我的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。if加上+1,while, for, foreach。在这种情况下有两条路径。如果someeconcondition为真,消息将被显示(第一个可能的路径),如果someeconcondition为假,消息将不被显示(第二个可能的路径)。
如果你看一下Windows窗体中Dispose的实现,它看起来是这样的:
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
这里圈复杂度是3。在&&两个值都必须为真,才能对其中的表达式求值。这意味着如果 disposing
都为真和 (components != null)
为真,则有第一条路径。如果disposing
为假,则有第二条路径。第三条路径来自components
可以为空的事实,因此它将计算为假。因此圈复杂度为3。
在switch
的情况下,你得到+1,对于每个case
(和default
)出现在里面,你得到+1。在您的方法中,有6条case
语句和1条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,但你就是不能理解正在写的东西。