Skip to content

BRO1309: Element names should begin with an upper-case letter

Types, methods, properties, events, enum members and local functions are PascalCase: GetTotal, not getTotal. Replaces StyleCop SA1300 (except for namespaces).

Example

Before

internal enum status
{
    open,
    closed,
}

internal class order
{
    public order(status initial)
    {
        state = initial;
    }

    public status state { get; private set; }

    public void close()
    {
        if (isOpen())
        {
            state = status.closed;
        }
    }

    private bool isOpen() => state == status.open;
}

After

internal enum Status
{
    Open,
    Closed,
}

internal class Order
{
    public Order(Status initial)
    {
        State = initial;
    }

    public Status State { get; private set; }

    public void Close()
    {
        if (IsOpen())
        {
            State = Status.Closed;
        }
    }

    private bool IsOpen() => State == Status.Open;
}

Why

PascalCase for types and members is the .NET convention: everything in the base class library and in almost every library you use is named that way, so code that follows it reads the same as the APIs it calls.

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 name is renamed everywhere in the solution, with its first letter capitalized (and leading underscores dropped): close becomes Close, _helper becomes Helper. For a type, its constructors and finalizer are renamed too.

A member of an interface or an abstract or virtual member takes its implementations and overrides along (explicit implementations included); without them the code wouldn't compile. Those aren't reported themselves (their name comes from the base, like in StyleCop).

Checked: classes, structs, records, enums, delegates, methods, properties, events, enum members and local functions. Interfaces are BRO1304's, fields BRO1303 and BRO1306-BRO1308's.

Renaming public types and members is a breaking change for code outside the solution, and files aren't renamed (dotnet format only changes file contents). Names used from non-C# files (XAML, Razor, configuration) aren't seen by the fix.

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).
  • The name appears in code excluded by #if anywhere in the project (a local function: #if in its member): disabled code isn't compiled, so the rename can't follow it.
  • Public API (unless stylebro_rename_public_api = true): Types, methods, properties, events and enum members that other assemblies see, that is public, protected or protected internal in types that are visible too. Renaming them breaks code outside the solution. 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.
  • Namespaces. Renaming a namespace also changes embedded resource names and breaks folder conventions.
  • snake_case names (an underscore after the first letter: device_id, load_all): usually a wire name (JSON, a protocol), and Device_id wouldn't be PascalCase either. A leading underscore alone is fine (_helper -> Helper).
  • External methods (extern, [DllImport], [LibraryImport]): a P/Invoke method's name is the native entry point.
  • Properties and enum members with attributes, usually serialization settings, and properties of types with a serializer attribute ([JsonObject], [DataContract], ...).
  • Members whose name is part of another member's name, like items next to ShouldSerializeitems() or itemsSpecified: Json.NET and XML serialization pair them by name.
  • Partial methods (both declarations have to change together), indexers and operators.
  • Types with a generated part and their members, like a Razor component's code-behind class (List.razor.cs): the markup uses those names and its generated half can't be renamed (found in eShopOnWeb).
  • Members that keep the name of what they override or implement, including members that implement an interface from a library.
  • The new name already means something where the element is declared: another member of the type or a base type (run() next to Run(int)), or a type or namespace in scope; for types, a type with that name anywhere in the solution. A local function is checked like a local variable (BRO1301).

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.

  • The name appears in a string anywhere in the solution. For instance properties and events, and enum members, that includes appearing inside a longer string, like test JSON: serializers write them by name. Static properties and events aren't written by serializers: only a string where code reaches a member by name counts for them (GetProperty("nbc"), a member-source attribute), not a URL or file name that contains the word (AngleSharp's test assets). For types, a qualified name counts too ("App.order").
  • Another property of the type keeps its name because of a string. Then all of the type's properties do: renaming only some would mix casings and change only part of what a serializer reads and writes (a JSON DTO with document in test JSON keeps percentage too).
  • A derived type already has a member with the new name, or some reference would see something else under it.
  • Generated code uses the name: a Razor page, or a source generator's output (also a name in one of its strings). Generated code is written again by its tool, so the rename can't change it.

Rename these by hand, or suppress the warning.

Compared with StyleCop

Same results as StyleCop, except namespaces and snake_case names (StyleCop reports device_id; its fix would write Device_id). StyleCop's own fix changes nothing under dotnet format.