Pangram verdict · v3.3
We believe that this text is a mix of AI and human-written content.
AI likelihood · overall
MixedArticle text · 1,354 words · 6 segments analyzed
May 25, 2026 9 minutes read Cyclomatic Complexity (or CC) in C# is a code metric that counts the number of linearly independent execution paths through a method. Concretely, it is computed as 1 plus the number of branching constructs in the method body (such as if, while, for, case, &&, ||, ?: and ??). The higher the score, the harder the method is to read, test and safely change. A score of 1 means a single straight path, around 10 is the traditional upper bound recommended by Thomas McCabe, and anything above 25 is flagged as excessive by Microsoft’s CA1502 analyzer. This guide explains, with C# examples, how Cyclomatic Complexity is calculated, what thresholds matter in practice, how to measure and visualize it in real .NET codebases, and how to go beyond the raw score by pairing it with test coverage and IL-level analysis.
Index What is Cyclomatic Complexity?Definition of Cyclomatic Complexity in C#Example of Cyclomatic Complexity Impact in C#Exhibiting a Complex MethodRefactoring the Complex Method in Several Simpler MethodsBenefits of RefactoringCyclomatic Complexity Thresholds: What Score Is Too High?Measuring Cyclomatic Complexity in C#Ruling C# Cyclomatic ComplexityVisualizing C# Cyclomatic ComplexityC# Cyclomatic Complexity and TestsGoing Beyond Cyclomatic ComplexityPair Complexity with Branch CoverageIL Cyclomatic Complexity for Third-Party CodeHow to Reduce Cyclomatic Complexity in C#1.
Extract Method2. Early Return / Guard Clauses3. Replace Conditionals with Polymorphism4. Use Modern C# Pattern Matching and Switch Expressions5. Use Lookup Tables for Pure Mappings6. Boolean Parameters Are a Code SmellFrequently Asked QuestionsWhat is a good Cyclomatic Complexity score in C#?Does the else keyword increase Cyclomatic Complexity?Does a switch statement count once or per case?Does Cyclomatic Complexity equal the number of unit tests I need?What is the difference between Cyclomatic Complexity and Cognitive Complexity?How do I measure Cyclomatic Complexity in Visual Studio?Does Cyclomatic Complexity work on async or LINQ code?Conclusion Cyclomatic Complexity was introduced by Thomas J. McCabe in 1976 as a way to quantify the structural complexity of a piece of code. The idea comes from graph theory: every method can be represented as a control flow graph where nodes are blocks of statements and edges are jumps between them. On that graph, the Cyclomatic Complexity is given by the classic formula: 1 M = E - N + 2P where E is the number of edges, N the number of nodes, and P the number of connected components. For a regular method with a single entry and a single exit, this collapses to 1 + the number of decision points, which is the form most tools actually compute. What this number really tells you is the minimum number of test cases you need to exercise every independent path through the method. That is why Cyclomatic Complexity has stuck around for almost half a century: it is a structural metric, but it has a very concrete operational meaning for everyone who has to maintain or test the code.
Definition of Cyclomatic Complexity in C# The Cyclomatic Complexity for a C# method is concretely 1 + {the number of following expressions found in the body of the method}: 12345 if while for foreachcase default continuegoto && || catchternary operator ?: ??and or The following expressions are not counted for CC computation: 12345 else do switch try usingthrow finally returnobject creationmethod callfield access Two details that trip people up: else does not increment the score because the alternative path was already created by its matching if; and a switch contributes one unit per case (and one for default), not one for the switch keyword itself. C# pattern-matching constructs (and, or, the modern switch expression with patterns) also add to the score, the same way their classic counterparts do. Example of Cyclomatic Complexity Impact in C# Exhibiting a Complex Method Here is a complex method with entangled if and else scopes. The keyword if is used six times and && is used once.
Hence its Cyclomatic Complexity score is 8: C 1234567891011121314151617181920212223242526272829303132333435 public static class OrderLogic { public static void ProcessOrder( int orderId, bool isPriority, bool isInternational, bool isGift, bool isCouponApplied, decimal orderTotal) { if (orderId <= 0) { Console.WriteLine("Invalid order ID."); return; } if (isPriority) { Console.WriteLine("Processing priority order."); if (isInternational) { Console.WriteLine("Processing international priority order."); if (isGift) { Console.WriteLine("This is a gift order."); } } } else { Console.WriteLine("Processing standard order."); if (isInternational) { Console.WriteLine("Processing international standard order."); } } if (isCouponApplied && orderTotal > 100) { Console.WriteLine("Applying discount for orders over $100."); } else { Console.WriteLine("No discount applicable."); } }} Eight independent paths means at least eight tests to fully cover this single method, plus a non-trivial amount of head-scratching every time someone has to add a new business rule. This is exactly the kind of method where a regression slips in unnoticed. Refactoring the Complex Method in Several Simpler Methods The method above can be refactored into several less complex methods. In the code we use CC to refer to each method Cyclomatic Complexity score: C 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 public static class OrderLogic { public static void ProcessOrder( int orderId, bool isPriority, bool isInternational, bool isGift, bool isCouponApplied, decimal orderTotal) { // CC 2 if (!IsValidOrder(orderId)) return; ProcessOrderType(isPriority, isInternational, isGift); ApplyDiscountIfEligible(isCouponApplied, orderTotal); } private static bool IsValidOrder(int orderId) { // CC 2 if (orderId <= 0) { Console.WriteLine("Invalid order ID."); return false; } return true; } private static void ProcessOrderType( bool isPriority, bool isInternational, bool isGift) { // CC 5 if (isPriority) { Console.WriteLine("Processing priority order."); if (isInternational) { Console.WriteLine("Processing international priority order."); } } else { Console.WriteLine("Processing standard order."); if (isInternational) { Console.WriteLine("Processing international standard order."); } } if (isGift) { Console.WriteLine("This is a gift order."); } } private static void ApplyDiscountIfEligible( // CC 3 bool isCouponApplied, decimal orderTotal) { if (isCouponApplied && orderTotal > 100) { Console.WriteLine("Applying discount for orders over $100."); } else { Console.WriteLine("No discount applicable."); } }} Benefits of Refactoring Simpler Control Flow: The main method now delegates specific tasks to smaller, more focused methods. Easier to Test: You can test each smaller method independently. Lower Cyclomatic Complexity: The complexity is spread across multiple methods, making each method easier to understand and maintain independently. Better Naming: Method names like IsValidOrder or ApplyDiscountIfEligible document intent, so a reader does not have to mentally simulate the body to understand the high-level flow. Note that the total Cyclomatic Complexity summed across the four methods is actually slightly higher than the original 8. That is fine and even expected. What matters for maintainability is the complexity per method, because that is the unit a developer has to reason about at a time. Cyclomatic Complexity Thresholds: What Score Is Too High? There is no single sacred number, but the literature converges around the same ranges. The table below summarises what most teams and tools use as a guideline: Cyclomatic Complexity Risk profile Practical interpretation 1 – 10 Simple, low risk McCabe’s original recommendation. Easy to test, easy to read. 11 – 20 Moderately complex Still manageable, but worth a second pair of eyes during review. 21 – 50 Complex, high risk Hard to test exhaustively. Strong refactoring candidate. > 50 Untestable Bug magnets. Often legacy hotspots that need to be broken down. Two reference points are worth keeping in mind. McCabe himself recommended splitting modules that exceed a Cyclomatic Complexity of 10. Microsoft’s CA1502 analyzer defines “excessive complexity” as a score greater than 25 by default. Mark Seemann argues for an even tighter ceiling of around 7, mirroring Miller’s “magical number seven, plus or minus two” for human short-term memory. In practice the right threshold depends on the codebase. A parser, a serializer or a state machine will routinely live in the 15-25 range without being objectively bad. A piece of business logic that scores 25 almost always is. Measuring Cyclomatic Complexity in C# You can’t improve what you don’t measure, so using a tool to evaluate code complexity is essential. Calculating this metric helps developers identify areas that might need refactoring to improve code quality.
NDepend is a great option for this, as it measures the cyclomatic complexity of methods in C# code. For instance, it includes the Search Methods by Complexity feature, which helps identify complex methods for further analysis.