C# 为什么这个函数的复杂性是12?

C# 为什么这个函数的复杂性是12?,c#,complexity-theory,cyclomatic-complexity,C#,Complexity Theory,Cyclomatic Complexity,我有一个(C#)函数,它检查四组条件并返回bool。如果其中任何一个为true,则返回true。我相信我可以简化逻辑,但我希望它相当可读 Visual Studio中的CodeMaid扩展告诉我函数的柱面复杂性是12。我和圆柱的复杂性是 通过源代码的独立路径数 我不明白为什么是12。我可以从两个方面考虑,圈复杂度应该是2,因为它总是通过相同的路径,但可能返回true或false。或者可以理解它是16,因为最后四个布尔值加在一起可能是真的,也可能是假的,2*2*2*2=16 有人能告诉我为什么是1

我有一个(C#)函数,它检查四组条件并返回bool。如果其中任何一个为true,则返回
true
。我相信我可以简化逻辑,但我希望它相当可读

Visual Studio中的CodeMaid扩展告诉我函数的柱面复杂性是12。我和圆柱的复杂性是

通过源代码的独立路径数

我不明白为什么是12。我可以从两个方面考虑,圈复杂度应该是2,因为它总是通过相同的路径,但可能返回
true
false
。或者可以理解它是16,因为最后四个布尔值加在一起可能是真的,也可能是假的,2*2*2*2=16

有人能告诉我为什么是12点吗?甚至可以显示一个图表,这样我就可以直观地看到不同的路径了

public bool FitsCheckBoxCriteria(TaskClass tasks)
{
    // note: bool == true/false comparisons mean you don't have to cast 'bool?' as bool


    // if neither checkboxes are checked, show everything
    bool showEverything = NoShutDownRequiredCheckBox.IsChecked == false &&
                          ActiveRequiredCheckBox.IsChecked == false; 

    // if both are checked, only show active non-shutdown tasks
    bool showActiveNonShutdown = ActiveRequiredCheckBox.IsChecked == true &&
                                 tasks.Active == "YES" &&
                                 NoShutDownRequiredCheckBox.IsChecked == true &&
                                 tasks.ShutdownRequired == "NO";

    // if active is checked but shudown isn't, display all active
    bool showActive = ActiveRequiredCheckBox.IsChecked == true &&
                      tasks.Active == "YES" &&
                      NoShutDownRequiredCheckBox.IsChecked == false;

    // if non-shutdown is checked but active isn't, display all non-shutdown tasks
    bool showNonShutdown = NoShutDownRequiredCheckBox.IsChecked == true &&
                           tasks.ShutdownRequired == "NO" &&
                           ActiveRequiredCheckBox.IsChecked == false;

    return showEverything || showActiveNonShutdown || showActive || showNonShutdown;
}
提前谢谢

编辑:

我把它改成了这个。为复选框条件指定局部变量没有任何效果,但通过“是”/“否”创建布尔值将复杂性提高到14,我想我理解这一点

public bool FitsCheckBoxCriteria(LubeTask tasks)
{
    bool noShutdownReqChecked = (bool)NoShutDownRequiredCheckBox.IsChecked;
    bool activeChecked = (bool)ActiveRequiredCheckBox.IsChecked;

    bool active = tasks.Active == "YES" ? true : false;
    bool shutdownReq = tasks.ShutdownRequired == "YES" ? true : false;

    // if neither checkboxes are checked, show everything
    bool showEverything = !noShutdownReqChecked && !activeChecked;

    // if both are checked, only show activeChecked non-shutdown tasks
    bool showActiveNonShutdown = activeChecked && noShutdownReqChecked && active && !shutdownReq;

    // if activeChecked is checked but shudown isn't, display all activeChecked
    bool showActive = activeChecked && !noShutdownReqChecked && active;

    // if non-shutdown is chceked but activeChecked isn't, display all non-shutdown tasks
    bool showNonShutdown = noShutdownReqChecked && !activeChecked && !shutdownReq;

    return showEverything || showActiveNonShutdown || showActive || showNonShutdown;
}

这只是一个猜测,但我认为对于return语句中的每个可能的退出条件,赋值都是+2(if=true/else=false),然后是+1。因此,它可能会放松到类似于:

bool showEverything = false;
if (...) { showEverything = true; } +1
else { showEverything = false; } +1

bool showActiveNonShutdown = ... +2 if/else
bool showActive = ... +2 if/else
bool showNonShutdown = ... +2 if/else

if (showEverything) {...} +1
else if (showActiveNonShutdown) {...} +1
else if (showActive) {...} +1
else if (showNonShutdown) {...} +1
else {false}
C#使用短路求值,这意味着如果存在
x&&y
表达式,则只有在必要时才对
y
求值,更准确地说,如果
x
为真。这意味着
result=x&&y
有两个独立的执行路径:(1)如果
x
为false,则只计算
x
,并且
result
获得false值(不计算
y
),但是(2)如果
x
为true,则也计算
y
并且
result
获得
y
的计算结果。这意味着每个
&
|
运算符都会增加圈复杂度,在第一个示例中,有8个&&&和3个| |运算符,因此该方法的圈复杂度为12。

关键在于“独立路径”

我将重写您的代码以缩短它,以便我们可以讨论它

public bool FitsCheckBoxCriteria(TaskClass tasks)
{
    bool E1 = A1 && A2; 

    bool E2 = B1 && B2 && B3 && B4;

    bool E3 = C1 && C2 && C3;

    bool E4 = D1 && D2 && D3;

    return E1 || E2 || E3 || E4;
}
圈复杂度是独立路径的数量。这不是返回值(2)的可能总数

&&运算符和| |运算符是短路操作;如果A1为假,则不计算A2。类似地,如果E1为真,则不计算E2

如果在上面的代码中用&替换所有的&&s,用|替换所有的| | s,圈复杂度为1,因为代码中只有一条路径。 (但这并不能使它更好地编写代码)

事实上,有72条可能的路径

  • 对A1、B1、C1、D1、E1进行评估;其他人则不然
  • 对A1、A2、B1、C1、D1、E1进行评估;其他人则不然
  • 对A1、B1、B2、C1、D1、E1进行评估;其他人则不然
  • 对A1、A2、B1、B2、C1、D1、E1进行评估;其他人则不然。 等等 但是,路径4不包含任何以前路径上没有的新代码。这就是“独立路径”的定义——每条路径必须包含新代码

    因此,在本例中,您可以手动计算代码,如下所示:

    1+此代码中短路操作员的数量(11)=12


    这是一种非常有趣的看待它的方式!奇怪的是,如果删除所有
    ==true
    语句并将
    ==false
    更改为
    ,复杂性会发生什么变化?他们是redundant@moarboilerplate我知道它们是多余的。只是这些类型是
    bool?
    而不是
    bool
    ,所以为了可读性起见,我没有将它们全部转换,而是进行了比较。是的,但它对复杂性有什么影响?另外,如果您有兴趣优化它,我会使用标志枚举和逐位操作为每一位设置权限(尽管这会消除布尔值的可空性)嗯,我去掉了比较并进行了强制转换,这并没有改变复杂性。不过,这会很好。