Field Differs From Base By Case

ID

csharp.field_differs_from_base_by_case

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

CSharp

Tags

code_smell, inheritance, naming, shadowing

Description

Reports a field of a derived class whose name differs from an inherited field’s name only by letter case — the two names are equal ignoring case, but not equal.

Two narrowings keep this to the confusing cases. A private base field is not compared: the derived class cannot see it, so the two names never share a scope. private protected fields are compared, since derived types in the same assembly do see them. A pair that is static on both sides is not reported either, because each is reached through its own type name. Base classes declared in other files are not compared.

Rationale

Both names are in scope inside the derived class, and no use site tells them apart. The statements are one keystroke apart and write to different storage:

public class Vehicle
{
    protected int wheelCount;
    public string Model;
    private int engineId;
    protected static int registry;
}

public class Truck : Vehicle
{
    private int WheelCount;          // FLAW - Vehicle.wheelCount is also in scope here
    private string model;            // FLAW - Vehicle.Model is also in scope here
    private int EngineId;            // OK - the base field is private and invisible here
    private static int Registry;     // OK - both are static, each reached through its type
    private int payload;             // OK - no inherited field of that name
}

Nobody reads the difference: reviewers skim the identifier, IDE completion offers both, and a later rename that normalises the casing of one of them silently redirects every assignment. If the derived field was meant to be the inherited one, the initialisation in the base class is being ignored and the object carries two half-populated values; if it was meant to be new state, its name gives no hint of what makes it different.

Remediation

If the two fields hold the same thing, delete the derived declaration and use the inherited field. If they hold different things, rename the derived one so the name says how it differs. When the inherited field is meant to be part of the derived type’s own state, prefer making it protected in the base class and assigning it from the derived constructor over redeclaring it.