User Rating 0.0
Total Usage 0 times
Input 0 lines · 0 chars
Output 0 lines · 0 chars
Is this tool helpful?

Your feedback helps us improve.

About

Inconsistent indentation and brace placement in C# codebases cause merge conflicts, obscure logic errors, and slow code reviews. A single misplaced closing brace } after a refactor can silently change control flow without triggering a compiler error. This tool parses your C# source through a state-machine tokenizer that distinguishes code from string literals (@"", $""), comments (//, /* */, ///), and preprocessor directives (#region, #if). It then applies deterministic indentation rules based on brace depth, normalizes blank lines between members, and positions braces according to your chosen convention (Allman or K&R).

The formatter handles edge cases including nested generic type parameters Dictionary<string, List<int>>, lambda expressions, LINQ query syntax, and switch expressions introduced in C# 8.0. It preserves content inside all string literal types and comment blocks verbatim. This tool approximates formatting behavior assuming syntactically valid C# input. Malformed code (unmatched braces, unterminated strings) will be formatted on a best-effort basis with a warning.

csharp beautifier csharp formatter code formatter csharp pretty print code beautifier csharp indent

Formulas

The beautifier operates as a two-phase pipeline: tokenization followed by reconstruction.

Tokenize(source) [T0, T1, … Tn]

Each token Ti carries a type classification and raw text. The tokenizer is a finite state machine with states: DEFAULT, IN_STRING, IN_VERBATIM_STRING, IN_INTERPOLATED_STRING, IN_RAW_STRING, IN_CHAR, IN_SINGLE_COMMENT, IN_MULTI_COMMENT, IN_PREPROCESSOR. Transitions are character-driven with one-character lookahead.

Format([T0Tn], indent, style) output

The formatter walks the token stream maintaining an indent depth counter d. On encountering {, it emits the brace (on current or new line per style), then increments: d d + 1. On }, it decrements first: d max(0, d 1), then emits the brace at the new depth. Each new line is prefixed with d × indent characters (spaces or tabs). Consecutive blank lines are collapsed: maximum 1 empty line between blocks.

Where indent = the configured indentation string (e.g., 4 spaces), style {Allman, K&R} determines whether opening braces appear on a new line or the same line as the controlling statement, and d 0 is clamped to prevent negative indentation from malformed input.

Reference Data

C# FeatureSyntax PatternFormatter HandlingSince Version
Namespace declarationnamespace X { }Brace on new line, contents indentedC# 1.0
File-scoped namespacenamespace X;Semicolon ends line, no brace indentC# 10
Verbatim string@"..."Content preserved, no formatting insideC# 1.0
Interpolated string$"...{expr}..."Content preserved, expressions untouchedC# 6.0
Raw string literal"""..."""Content preserved verbatimC# 11
XML doc comment/// <summary>Preserved at current indent levelC# 1.0
Multi-line comment/* ... */Content preserved, indent first line onlyC# 1.0
Preprocessor directive#if, #region, #pragmaPlaced at column 0 (no indentation)C# 1.0
Lambda expressionx => x + 1Kept inline, multi-line body indentedC# 3.0
LINQ queryfrom x in y select zEach clause on new indented lineC# 3.0
Switch expressionx switch { ... }Arms indented inside bracesC# 8.0
Pattern matchingis { Prop: value }Braces formatted at expression levelC# 7.0
Record typerecord Person(string Name);Positional params kept inlineC# 9.0
Init-only setterinit;Formatted as normal property accessorC# 9.0
Top-level statementsConsole.WriteLine();Formatted at indent level 0C# 9.0
Global usingglobal using System;Kept at top, no indentationC# 10
Attribute[Serializable]Own line, aligned with target memberC# 1.0
Generic constraintswhere T : classIndented under declarationC# 2.0
Async/Awaitasync Task Method()Keywords kept inline with signatureC# 5.0
Null-conditionalx?.PropertyNo whitespace inserted around ?.C# 6.0

Frequently Asked Questions

The tokenizer uses a state machine that enters a protected state (IN_STRING, IN_VERBATIM_STRING, IN_INTERPOLATED_STRING, IN_RAW_STRING, IN_SINGLE_COMMENT, IN_MULTI_COMMENT) upon encountering the opening delimiter. While in any protected state, characters including braces, semicolons, and newlines are captured verbatim into the token's raw text without triggering any formatting rules. The state only exits when the matching closing delimiter is found (accounting for escape sequences like \" in regular strings and "" in verbatim strings). This guarantees zero corruption of string content or comment text.
Allman style (the .NET convention recommended by Microsoft) places the opening brace on its own new line, aligned with the controlling statement. K&R style places the opening brace at the end of the controlling statement's line, separated by a space. For example, in Allman: "if (x)\n{" versus K&R: "if (x) {". The formatter applies the chosen style consistently to all brace-delimited blocks including namespaces, classes, methods, conditionals, loops, and switch statements. Most C# projects use Allman per the .NET Framework Design Guidelines.
Preprocessor directives in C# must begin at the start of a line (column 0) per the language specification. The formatter detects lines starting with # and outputs them with zero indentation regardless of the current brace depth. The content following the directive (e.g., the condition in #if DEBUG) is preserved exactly as written. Nested #if/#elif/#else/#endif blocks maintain their own logical structure but do not affect the indentation depth of the surrounding C# code.
The formatter operates on a best-effort basis for malformed input. Unmatched opening braces will cause increasing indentation that never returns to baseline. Unmatched closing braces will cause the indent depth to clamp at 0 rather than going negative. Unterminated string literals will cause all subsequent code to be treated as string content (no formatting applied). The tool displays a warning when brace counts are unbalanced. It does not validate C# syntax; it only applies structural formatting based on delimiter analysis.
Raw string literals delimited by three or more double-quote characters (e.g., """...content...""") are detected by the tokenizer when it encounters three consecutive quote characters. The tokenizer counts the opening quotes and only exits the raw string state when it finds the same number of consecutive closing quotes. All content between the delimiters, including braces, semicolons, and newlines, is preserved exactly. The opening and closing quote sequences remain on their original lines.
No. Indentation depth is purely brace-driven. Each opening brace increments depth by 1, each closing brace decrements by 1 (minimum 0). If your file contains two sequential namespace blocks, the first closing brace returns depth to 0, and the second namespace's opening brace starts fresh. For file-scoped namespaces (namespace X;), no braces are involved, so subsequent class declarations are indented at depth 0 unless they contain their own braces. The formatter inserts one blank line between top-level type declarations for readability.