Skip to content

BRO1505: Elements should be separated by a blank line

Members, types and namespaces are separated by a blank line; consecutive fields may stay together, unless the first spans several lines (a multi-line initializer), and so may consecutive single-line properties. Replaces StyleCop SA1516.

Example

Before

using System;
namespace Shop
{
    public class Cart
    {
        private readonly decimal _vat = 0.25m;
        private decimal _net;
        public event EventHandler? Changed;
        public decimal Total => _net * (1 + _vat);
        public void Add(decimal price)
        {
            _net += price;
            Changed?.Invoke(this, EventArgs.Empty);
        }
        /// <summary>Empties the cart.</summary>
        public void Clear() => _net = 0;
    }
}

After

using System;

namespace Shop
{
    public class Cart
    {
        private readonly decimal _vat = 0.25m;
        private decimal _net;

        public event EventHandler? Changed;

        public decimal Total => _net * (1 + _vat);

        public void Add(decimal price)
        {
            _net += price;
            Changed?.Invoke(this, EventArgs.Empty);
        }

        /// <summary>Empties the cart.</summary>
        public void Clear() => _net = 0;
    }
}

Why

Blank lines between members make the structure of a type visible at a glance, and let each member's comments and attributes clearly belong to it. Fields are usually read together, so they may stay in one block.

What is reported

An element that directly follows another element without a blank line in between:

  • members of classes, structs, records and interfaces
  • types and namespaces, and the first element after the using directives, assembly attributes or a file-scoped namespace X;
  • accessors, when either of two neighbouring accessors spans several lines

A blank line anywhere between the two counts, also one between an element's comment or #if and its code. Like StyleCop, these may stay together: two fields, two using directives, two extern aliases, two attribute lists, and single-line accessors (get { ... } above set { ... }). Like StyleCop's unreleased master, two properties may too when neither spans several lines (int A { get; set; } directly above int B { get; set; }) and neither has a /// documentation comment. A documented property is set apart like any other member: with BRO1601 adding /// <inheritdoc/> to some properties of a list, which of them ended up separated depended on the order dotnet format ran the fixes in (found in Ocelot); BRO1601's fix adds the blank line below the property it documents too.

How the fix works

The blank line goes above the element's first line: above its comments, XML docs and attributes, or above an #if around it. Two members on one line are split, with a blank line between and the same indentation.

Not reported

  • Two elements on one line with a comment between them. The fix would have to move the comment.
  • Enum members, which aren't elements in this sense.
  • Single-line members without a block body next to each other, with stylebro_allow_adjacent_single_line_members (see Configuration).

A field or property counts as spanning several lines from the line its attributes end on, like in StyleCop: [Obsolete] on its own line above private int a; doesn't make it multi-line. While BRO1527 is on, an auto-property it puts on one line ({ get; set; } spread over several lines) already counts as one line, so the blank line next to it doesn't depend on which fix dotnet format runs first.

Configuration

[*.cs]
stylebro_allow_adjacent_single_line_members = false
  • false (default): like StyleCop, only the pairs listed under What is reported may sit together.
  • true: two neighbouring single-line members without a block body may sit together too: methods, operators and conversion operators that are bodiless or expression-bodied, properties, indexers and events whose accessors have no block body, and field-like events, in any combination (StyleCop issue #2441). For example:
public abstract void Open();
public int Count() => items.Count;
public int this[int i] => items[i];
public event EventHandler? Changed;

Still separated with true: a member with a block body, even { } on one line (BRO1509 expands it); a method with where clauses (BRO1111 may put them on their own lines); a member that spans several lines; constructors, finalizers, fields, types and everything else next to them. BRO1001's sort, BRO1114's split of event fields and BRO1509's expansion of a one-line type follow the setting, so they add the blank line only where this rule wants one.

Compared with StyleCop

Same positions as StyleCop 1.2.0-beta.556, except two single-line undocumented properties: they may sit together, like in StyleCop's master (unreleased, 2aeb4e3d; the owner's decision, see decisions), where beta.556 wants a blank line between them. (master also wants one between two fields when the second spans several lines; StyleBro, like beta.556, only looks at the first.) StyleCop's fix leaves out the blank line above a /// doc comment, and when it splits two members on one line it leaves a trailing space and no indentation.