我们有这样的代码,算是吧。
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。
没有任何分支发生,这怎么可能?
请记住,代码分析看的是你的汇编中的IL,而不是你的源代码。IL中没有任何东西是原生支持lambda表达式的,所以它们是编译器的构造。你可以找到输出内容的具体细节。此处. 但基本上,你的lambda表达式被变成了一个私有的静态类,它是一个匿名的委托。然而,每次在代码中引用匿名委托时,都会创建一个匿名委托的实例,而不是将其缓存起来。所以每次分配一个lambda表达式时,它都会检查是否已经创建了一个lambda delegate的实例,如果创建了,它就会使用缓存的 delegate。所以在这个函数中,复杂度是1 + 2*(lambda express) = 1 + 2 *(13) = 27,这是正确的数字。
实际上,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。),我们可以希望它最终会出现。 目前,如果你觉得这个问题是假阳性的话,你几乎要忽略这个问题。
最好的猜测是,这可能是由于上面的语句被转换为事件访问器格式,即
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 用于讨论事件接入器的格式。