Cognitive Complexity, Because Testability != Understandability
Cyclomatic Complexity
Cognitive Complexity
With those rules in mind, let's take another look at those first two methods:
As I mentioned, one of the biggest beefs with Cyclomatic Complexity has been its treatment of switch statements. Cognitive Complexity, on the other hand, only increments once for the entire switch structure, cases and all. Why? In short, because switches are easy, and Cognitive Complexity is about estimating how hard or easy control flow is to understand.
On the other hand, Cognitive Complexity increments in a familiar way for the other control flow structures: for, while, do while, ternary operators, if/#if/#ifdef/..., else if/elsif/elif/..., and else, as well as for catch statements. Additionally, it increments for jumps to labels (goto, break, and continue) and for each level of control flow nesting:
As you can see, Cognitive Complexity takes into account the things that make this method harder to understand than getWords - the nesting and the continue to a label. So that while the two methods have equal Cyclomatic Complexity scores, their Cognitive Complexity scores clearly reflect the dramatic difference between them in understandability.
In looking at these examples, you may have noticed that Cognitive Complexity doesn't increment for the method itself. That means that simple domain classes have a Cognitive Complexity of zero:
So now class-level metrics become meaningful. You can look at a list of classes and their Cognitive Complexity scores and know that when you see a high number, it really means there's a lot of logic in the class, not just a lot of methods.
PDF https://www.sonarsource.com/docs/CognitiveComplexity.pdf
Sequences of logical operators
For similar reasons, Cognitive Complexity does not increment for each binary logical operator. Instead, it assesses a fundamental increment for each sequence of binary logical operators.
For instance, consider the following pairs:
a && ba && b && c && d
a || ba || b || c || d
Understanding the second line in each pair isn’t that much harder than understanding the first.
On the other hand, there is a marked difference in the effort to understand the following two lines:
a && b && c && d
a || b && c || d
Because boolean expressions become more difficult to understand with mixed operators, Cognitive complexity increments for each new sequence of like operators. For instance
优化的话,只能把复杂的部分,拆分到另外一个方法里面。然后让原来的方法调用新的方法。
https://www.cnblogs.com/chucklu/p/12671821.html 只要是调用深度不是层层嵌套,就还可以接受
How can the cyclomatic complexity be 27 in a method with 13 event handler subscriptions?
Remember that the Code Analysis is looking at the IL in your assembly, not your source code. There is nothing in the IL that natively supports lambda expressions, so they are a construct of the compiler. You can find the specifics of what is ouput here. But basically your lambda expression is turned into a private static class that is an anonymous deligate. However, rather that create an instance of the anonymous deligate every time it is referenced in code, the deligate is cached. So each time you assign a lambda expression, it does a check to see an instance of that lambda deligate has been created, if so it uses the cached deligate. That generates an if/else in the IL increasing the complexity by 2. So in this functions complexity is 1 + 2*(lambda express) = 1 + 2 *(13) = 27 which is the correct number.
Does LINQ and Lambda expressions reduce Cyclomatic-complexity?
I suspect that the discrepancy may be due to deferred execution. When you use LINQ with lambda expressions, you're specifying code which will be run if you then iterate over the collection.
Personally I'm not so worried about cyclomatic complexity, but I'm absolutely sure that (when used appropriately) LINQ improves readability. That's what I really care about :)