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.