在一个有13个事件处理程序订阅的方法中,循环复杂度怎么可能是27?

问题描述 投票:8回答:3

我们有这样的代码,算是吧。

private void InitializeEvents()
{
    this.Event1 += (s,e) => { };
    this.Event2 += (s,e) => { };
    this.Event3 += (s,e) => { };
    this.Event4 += (s,e) => { };
    this.Event5 += (s,e) => { };
    this.Event6 += (s,e) => { };
    this.Event7 += (s,e) => { };
    this.Event8 += (s,e) => { };
    this.Event9 += (s,e) => { };
    this.Event10 += (s,e) => { };
    this.Event11 += (s,e) => { };
    this.Event12 += (s,e) => { };
    this.Event13 += (s,e) => { };
}

在VS10终极版中的代码分析显示 "循环复杂度为27" 去掉其中一行,循环复杂度为25。

没有任何分支发生,这怎么可能?

c# code-analysis fxcop code-metrics cyclomatic-complexity
3个回答
17
投票

请记住,代码分析看的是你的汇编中的IL,而不是你的源代码。IL中没有任何东西是原生支持lambda表达式的,所以它们是编译器的构造。你可以找到输出内容的具体细节。此处. 但基本上,你的lambda表达式被变成了一个私有的静态类,它是一个匿名的委托。然而,每次在代码中引用匿名委托时,都会创建一个匿名委托的实例,而不是将其缓存起来。所以每次分配一个lambda表达式时,它都会检查是否已经创建了一个lambda delegate的实例,如果创建了,它就会使用缓存的 delegate。所以在这个函数中,复杂度是1 + 2*(lambda express) = 1 + 2 *(13) = 27,这是正确的数字。


3
投票

实际上,C#编译器为匿名方法生成了一些相当 "有趣 "的IL,包括lambdas。 对于每一个方法,它都会创建一个私有字段,然后在消耗方法中分配其值之前,它检查该值是否为空,这就为编译方法添加了一个If分支。 代码度量工具应该忽略这一点(http:/social.msdn.microsoft.comForumseuvstscodethread8c17f569-5ee3-4d26-bf09-4ad4f9289705, https:/connect.microsoft.comVisualStudiofeedbackdetails555560method-using-many-lambda-expressions-causes-high-cyclomatic-complexity。),我们可以希望它最终会出现。 目前,如果你觉得这个问题是假阳性的话,你几乎要忽略这个问题。


1
投票

最好的猜测是,这可能是由于上面的语句被转换为事件访问器格式,即

class MyClass
{
  private event EventHandler MyPrivateEvent;

  public event EventHandler MyEvent
  {
    add
    {
      MyPrivateEvent += value;
    }
    remove
    {
      MyPrivateEvent -= value;
    }
  }
}

请看 http:/msdn.microsoft.comen-usmagazinecc163533.aspx。http:/www.switchonthecode.comtutorialscsharp-tutorial-event-accessors 用于讨论事件接入器的格式。

© www.soinside.com 2019 - 2024. All rights reserved.