Skip to content

BRO1307: Field names should not begin with a prefix

Fields aren't named m_count, s_count or t_count. Replaces StyleCop SA1308.

Example

Before

public class Session
{
    private static int s_opened;
    private readonly string m_user;

    public Session(string user)
    {
        m_user = user;
        s_opened++;
    }

    public string Describe() => m_user + " (" + s_opened + " open)";
}

After

public class Session
{
    private static int opened;
    private readonly string user;

    public Session(string user)
    {
        this.user = user;
        opened++;
    }

    public string Describe() => user + " (" + opened + " open)";
}

Why

Hungarian-style prefixes repeat what the declaration already says (member, static, thread-static) and make names harder to read.

The .NET runtime's own style does use s_ for static fields and t_ for thread-static fields. If you follow that style, turn this rule off:

[*.cs]
dotnet_diagnostic.BRO1307.severity = none

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 field is renamed everywhere, and the new name is the complete correct name in one step: the prefix goes, any underscores inside the name go (BRO1308), and the casing follows the field's kind: camelCase for private fields (_camelCase if stylebro_private_field_naming says so, see BRO1303), PascalCase for constants, static readonly and non-private fields (BRO1306), camelCase for protected fields. So m_with_more becomes withMore, and m_Upper becomes upper. References that a local or parameter would hide are qualified (this.user).

Only the lower-case prefixes m_, s_ and t_ count, like in StyleCop; other x_ names are BRO1308's.

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.
  • Public API (unless stylebro_rename_public_api = true): Fields 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.
  • A prefix your naming rules ask for: when an active dotnet_naming_rule for fields uses a style with required_prefix = s_ (the .NET runtime's convention for static fields), s_ names are left alone.

  • Fields in a class whose name ends in NativeMethods (or a type nested in one), like StyleCop: they hold Win32 and COM names.

  • Interop names: SCREAMING_CASE constants and static readonly fields (S_OK), COM GUID fields (IID_...), and the fields of interop-shaped types ([StructLayout], [ComImport], [DllImport] methods); see BRO1308.
  • Names that would be empty, a keyword or field (m_, s_static, m_field; see BRO1303).
  • The same unsafe cases as BRO1303: a member with the new name, two fields getting the same name, attributes (a t_ field usually has [ThreadStatic], so it's left alone) or a [Serializable] type, the name in a string, in #if-excluded code, or as an inferred anonymous type member or tuple element 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 fields, except the skipped cases above (StyleCop turns s_static into @static). StyleCop's fix only removes the prefix (m_Upper becomes Upper, which then breaks SA1306), and m_with_more needs a second run for SA1310.