Avoid fields with same name in class hierarchy

Rule ND2019 Naming Conventions

Matches a field whose name is already used in the base class hierarchy. Compilers allow it (even when the base field is visible to derived classes), but it is likely an erroneous attempt to redefine a field.

How to fix

If the derived field is indeed a redefinition (same field type; for statics, a single instance suffices), delete it and make the base field protected. Otherwise rename the derived field, carefully renaming all its usages (they might relate to the base field).

CQLinq source

This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.

// <Name>Avoid fields with same name in class hierarchy</Name>
// <Id>ND2019:AvoidFieldsWithSameNameInClassHierarchy</Id>

warnif count > 0 

// Optimization: only consider fields of derived classes
let derivedClasses = Application.Types.Where(t =>
       t.IsClass &&
      !t.IsStatic &&
       t.DepthOfInheritance > 1 &&
       t.BaseClasses.ChildFields().Any())

from f in derivedClasses.ChildFields()
where JustMyCode.Contains(f) // Make sure it is fixable by targeting only JustMyCode fields
let fieldsOfBaseClassesWithSameName = 
      f.ParentType
       .BaseClasses
       .ChildFields()
       .Where(cf => cf.Name == f.Name && JustMyCode.Contains(cf))
where fieldsOfBaseClassesWithSameName.Any()

select new { 
  f, 
  fieldsOfBaseClassesWithSameName,
  baseClasses = fieldsOfBaseClassesWithSameName.Select(f1 => f1.ParentType).ToArray(),
  Debt = 10.ToMinutes().ToDebt(),
  Severity = Severity.Medium
}

//<Expl>
// There {2?is:are} {2?a:} field{2?:s} with same name as *{0}* in the base class{2?:es}: *{2}*.
// Investigate this ambiguous situation. It might reveal an incorrect attempt to redeclare a field in a derived class.
//</Expl>

//<Desc>
// Matches a field whose name is already used in the base class hierarchy.
// Compilers allow it (even when the base field is visible to derived
// classes), but it is likely an erroneous attempt to redefine a field.
//</Desc>

//<HowToFix>
// If the derived field is indeed a redefinition (same field type; for
// statics, a single instance suffices), delete it and make the base field
// *protected*. Otherwise rename the derived field, carefully renaming all
// its usages (they might relate to the base field).
//</HowToFix>

Naming Conventions: all 23 items