在具有13个事件处理程序订阅的方法中,圈复杂度如何才能成为27?

时间:2012-04-20 10:05:50

标签: c# code-analysis fxcop code-metrics cyclomatic-complexity

我们有这个代码,排序:

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 Ultimate中的代码分析称“圈复杂度为27”。删除其中一条线会使圈复杂度达到25。

没有分支,所以这怎么可能?

3 个答案:

答案 0 :(得分:17)

请记住,代码分析正在查看程序集中的IL,而不是源代码。 IL中没有任何内容支持lambda表达式,因此它们是编译器的构造。您可以找到ouput here的具体信息。但基本上你的lambda表达式变成了一个私有的静态类,它是一个匿名的deligate。但是,每次在代码中引用匿名deligate的实例时,都会缓存deligate。因此,每次分配一个lambda表达式时,它都会检查是否已创建该lambda deligate的实例,如果是,则使用缓存的deligate。这会在IL中生成if / else,使复杂度增加2.因此,在此函数中,复杂度为1 + 2 *(lambda express)= 1 + 2 *(13)= 27这是正确的数字。

答案 1 :(得分:3)

C#编译器实际上为匿名方法生成了一些相当“有趣”的IL,包括lambdas。对于每一个,它创建一个私有字段,然后在使用consume方法中的值分配之前,它检查该值是否为null,这会将If分支添加到已编译的方法中。代码度量工具应该忽略这个(http://social.msdn.microsoft.com/Forums/eu/vstscode/thread/8c17f569-5ee3-4d26-bf09-4ad4f9289705,https://connect.microsoft.com/VisualStudio/feedback/details/555560/method-using-many-lambda-expressions-causes-high-cyclomatic-complexity),我们希望它最终会。现在,如果您觉得这是一个误报,那么你几乎不得不忽视这个问题。

答案 2 :(得分:1)

最好的猜测是,这可能是由于上述声明被转换为事件访问者格式,即

class MyClass
{
  private event EventHandler MyPrivateEvent;

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

请参阅http://msdn.microsoft.com/en-us/magazine/cc163533.aspxhttp://www.switchonthecode.com/tutorials/csharp-tutorial-event-accessors 讨论事件访问者格式。