Skip to content

BRO1508: A block should not be on a single line

A statement's block (if, else, loops, using, lock, try/catch/finally, a standalone { }) puts its braces and each statement on their own lines. Replaces StyleCop SA1501.

Example

Before

public class Account
{
    public decimal Balance { get; private set; }

    public void Withdraw(decimal amount)
    {
        if (amount <= 0) { return; }
        if (amount > this.Balance) { throw new System.InvalidOperationException(); } else { this.Balance -= amount; }
    }
}

After

public class Account
{
    public decimal Balance { get; private set; }

    public void Withdraw(decimal amount)
    {
        if (amount <= 0)
        {
            return;
        }

        if (amount > this.Balance)
        {
            throw new System.InvalidOperationException();
        }
        else
        {
            this.Balance -= amount;
        }
    }
}

Why

A one-line block hides control flow at the end of a line, and adding a second statement means reformatting the whole block. Blocks laid out the same way everywhere are faster to scan.

How the fix works

The braces get their own lines at the indentation of the statement, the statements inside go one level deeper (from indent_style/indent_size in .editorconfig), and an empty block becomes { and } on two lines. else, catch and finally that followed the } move to their own line. The fix only rewrites the spaces between those tokens, so the code itself and the file's line endings stay as they are. Nested one-line blocks are expanded in one pass. When BRO1519 is on, a statement after the expanded block gets its blank line in the same pass, and so does a statement inside that BRO1514, BRO1515 or BRO1516 wants braces on (if (a) { if (b) return; }): those rules leave the statements of a one-line block to this fix, so one dotnet format run is enough. A block inside a one-line method body (void M(bool x) { if (x) { return; } }) expands the body too when BRO1509 is on: expanding only the inner block would leave void M(bool x) { if (x) on a line, which no rule reports any more. With csharp_preserve_single_line_statements = false a statement without braces (if (x) y;, loops, else) gets its embedded statement on its own line, one level deeper, as the SDK's whitespace formatting would do once the block isn't on one line (it runs before the fixes, so otherwise a second run). A braced one (if (x) { y; } else z;) keeps its block on one line, with the { and else on their own lines as csharp_new_line_before_open_brace and csharp_new_line_before_else say.

The SDK's settings are respected: with csharp_new_line_before_open_brace not including control_blocks, the { stays at the end of the statement's line (if (x) {), and csharp_new_line_before_else = false keeps } else {. do { ... } while (x); keeps while after the }.

Configuration

[*.cs]
# false (default, like StyleCop): an empty block on one line is expanded too.
# true: an empty block on one line ('catch { }', 'while (Next()) { }'; whitespace only) stays.
stylebro_allow_empty_single_line_blocks = false

The key is shared with BRO1509, which then leaves empty member bodies and types on one line too. With true, try { Run(); } catch { } becomes:

try
{
    Run();
}
catch { }

Not reported

  • Lambda and anonymous-method bodies (() => { Run(); }), like StyleCop.
  • A comment inside the braces ({ /* note */ return; }): the fix would have to move it.
  • A comment after the } on its line (catch (IOException) { } // slopwatch-ignore: SW003 ...): expanded, the comment would end up on the } line, away from the statement a line-based suppression marks. A one-line block inside such a block stays too.
  • A block that shares its line with code that stays there, like case 1: { ... } inside a switch (x) { ... } written on one line: there's no line to indent it from.
  • Method and local function bodies are BRO1509's.

Compared with StyleCop

Same positions as StyleCop, except the cases under "Not reported" above. StyleCop's fix misindents nested blocks (it writes { at the start of the line), moves while of do ... while to its own line, and writes Windows line endings into files that use \n.