Skip to content

BRO1302: Parameter names should begin with a lower-case letter

Parameters are camelCase: count, not Count or _count. Replaces StyleCop SA1313.

Example

Before

internal abstract class Shape
{
    /// <summary>Scales the shape.</summary>
    /// <param name="Factor">How much to scale by.</param>
    public abstract void Scale(double Factor);
}

internal class Circle : Shape
{
    public double Radius { get; private set; } = 1;

    public override void Scale(double Factor) => Radius *= Factor;

    public static Circle Create() => new Circle().Resized(Factor: 2);

    private Circle Resized(double Factor)
    {
        Scale(Factor);
        return this;
    }
}

After

internal abstract class Shape
{
    /// <summary>Scales the shape.</summary>
    /// <param name="factor">How much to scale by.</param>
    public abstract void Scale(double factor);
}

internal class Circle : Shape
{
    public double Radius { get; private set; } = 1;

    public override void Scale(double factor) => Radius *= factor;

    public static Circle Create() => new Circle().Resized(factor: 2);

    private Circle Resized(double factor)
    {
        Scale(factor);
        return this;
    }
}

Why

C# names locals and parameters in camelCase and everything else in PascalCase, so the case tells you at a glance whether a name belongs to the method. For parameters it's also part of the API: callers see the names in IntelliSense and use them in named arguments.

Configuration

stylebro_rename_public_api = true also renames names other assemblies see (default false, see Not reported; the owner's decision in decisions.md).

How the fix works

The parameter and every use of it are renamed, anywhere in the solution: the body, nameof, named arguments (Resized(Factor: 2)) and the <param>/<paramref> docs. The new name is built like for BRO1301: Count becomes count, _count becomes count, URL becomes url, MAX_COUNT becomes maxCount.

A parameter of an abstract, virtual or interface member takes the parameters of its overrides and implementations along when they have the same name, so they stay in sync. Those parameters aren't reported themselves (their name comes from the base, like in StyleCop); one that has a different name is reported on its own.

Checked: parameters of methods, constructors (including primary constructors of classes and structs), indexers, operators, delegates, local functions, lambdas and anonymous methods.

Renaming a public parameter is a source-breaking change for callers outside the solution that use it as a named argument. Code inside the solution is updated.

The name can reach run time. nameof(Path) becomes nameof(path), and ArgumentNullException.ThrowIfNull(Path) reads the name through [CallerArgumentExpression], so an exception's ParamName changes from "Path" to "path". Like StyleCop's SA1313 fix, the rename goes ahead: the new name is what the parameter is called now, and a test that compares ParamName with the old spelling needs the same update. (BRO1313 is different: it renames a parameter that already has a consistent name only to match its base, so it keeps such names; see decisions.md.)

Not reported

  • Where IDE1006 is suppressed: after #pragma warning disable IDE1006 (up to its restore), or with [SuppressMessage("Style", "IDE1006")] on the declaration, its member or type, or a global one targeting them. Code that opts out of the SDK's naming rules (a file copied from another project) keeps its names.
  • A new name your SDK naming rule rejects: when the first dotnet_naming_rule that covers the symbol is enforced (IDE1006, or the rule's own severity, at suggestion or above) and asks for another style, like _camelCase for private properties, the name stays (renaming it would only trade this warning for IDE1006).
  • Public API (unless stylebro_rename_public_api = true): Parameters of methods, constructors, indexers and delegates that other assemblies see, that is public, protected or protected internal in types that are visible too. Renaming them breaks code outside the solution (named arguments use parameter names). Internal code is renamed, also with InternalsVisibleTo.
  • A name that nameof(...) produces: the rename would change the string (Ocelot built an HTTP header name with nameof(X_RateLimit_Limit), and a test read a private field with GetField(nameof(_components))). Looked for in the member for variables and parameters, in the type for fields; the fix also looks in the rest of the solution and leaves the warning when it finds one.
  • Record parameters (record Person(string Name)): they become properties, which are PascalCase.
  • Parameters that keep the name of the parameter they override or implement.
  • Partial methods. Both declarations have to be renamed together.
  • Constructor parameters named exactly like a property or field of their type (Point(int X) { this.X = X; }). Serializers bind constructor parameters to members by name, and some (CsvHelper) case-sensitively, so X -> x would compile and then fail to load data. Found through CsvHelper's tests.
  • Names in an expression tree: parameters of a lambda that end up in a System.Linq.Expressions tree (an Expression<Func<...>> lambda, a query method on IQueryable, or a lambda nested in one). The names are data at run time: they show in the expression's ToString() and query providers may use them (Mapster's tests compare a query's text). StyleCop's SA1313 reports them.
  • The same unsafe cases as BRO1301: the new name is already used in the member, two names would get the same new name, the parameter names an anonymous type member or tuple element by inference, the member contains #if, or the name has no camelCase form (_, _1, Class, Field), or would be value in an indexer.

When an override can't be renamed safely (its member already uses the new name), the base and the other overrides are renamed and that override keeps its name.

Reported but not fixed

If dotnet format leaves a finding, StyleBro kept it on purpose. The fix looks at the whole solution, other projects included, which the analyzer can't see, and leaves a change that would break something there: the name in a string or a nameof (reflection, serialization), a member that would hide it, a use in generated code. It offers no code action for such a finding, and stylebro-migrate format lists each one with its reason (Findings kept on purpose); its --verify-no-changes doesn't fail on them. Change it by hand only after checking those uses, or suppress it or record it in the baseline.

Compared with StyleCop

Same results as StyleCop, except for the skipped cases above; StyleCop reports _ and __ parameters. StyleCop's fix for SA1313 only lowers the first letter, can't fix names that start with _, leaves overrides and implementations behind (they are then reported), and under dotnet format applies only some of the renames per run.