Skip to content

BRO1304: Interface names should begin with I

Interfaces are named IShape, not Shape. Replaces StyleCop SA1302.

Example

Before

internal interface Shape
{
    double Area();
}

internal class Square : Shape
{
    public double Side { get; set; }

    public double Area() => Side * Side;

    public static double Total(Shape[] shapes)
    {
        double total = 0;
        foreach (Shape shape in shapes)
        {
            total += shape.Area();
        }

        return total;
    }
}

After

internal interface IShape
{
    double Area();
}

internal class Square : IShape
{
    public double Side { get; set; }

    public double Area() => Side * Side;

    public static double Total(IShape[] shapes)
    {
        double total = 0;
        foreach (IShape shape in shapes)
        {
            total += shape.Area();
        }

        return total;
    }
}

Why

The I prefix is the .NET convention: it tells you at a glance that a type is a contract, not a class you can create.

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 interface is renamed everywhere in the solution: declarations (every part of a partial interface), base lists, types of variables and parameters, typeof, nameof and cref references. The new name is I plus the name with its first letter capitalized: Shape becomes IShape, iShape becomes IShape, _Shape becomes IShape.

Like StyleCop, only the first letter is checked, so Item is a fine interface name.

The file isn't renamed. dotnet format only changes file contents, so Shape.cs keeps its name; rename it by hand if you keep file names in sync with type names. Renaming a public interface is a breaking change for code outside the solution.

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: disabled code isn't compiled, so the rename can't follow it (and stylebro-migrate format formats one target framework at a time).
  • Public API (unless stylebro_rename_public_api = true): Interfaces 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.
  • The new name already means something: a type with that name anywhere in the solution, or a member, type parameter or imported type with that name where the interface is declared.

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 interface's name appears in a string anywhere in the solution, alone or qualified ("App.Shape", "App.Shape, App"): code can load types by name (Type.GetType, dependency injection, serializers), and the rename would still compile but fail at run time.
  • A reference somewhere else would see a different type with the new name, for example a file with using System.Collections; that uses an interface Enumerable (it would become IEnumerable).

Rename these by hand, or suppress the warning.

Compared with StyleCop

Same results as StyleCop. StyleCop's own fix changes nothing under dotnet format.