Do not hide base class methods
Method hiding: a base class defines non-virtual M() and a derived class also defines M() with the same signature, so base.M() and derived.M() behave differently — not polymorphism, where both invoke the same implementation on a derived instance. This leads to confusion; this rule warns about all such cases.
How to fix
Remove or rename the method, or change its parameter signature so it no longer hides the base method. Legitimate hiding (same name, different behavior) is very rare, see: https://learn.microsoft.com/en-us/archive/blogs/ericlippert/method-hiding-apologia
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>Do not hide base class methods</Name>
// <Id>ND1205:DoNotHideBaseClassMethods</Id>
warnif count > 0
// Define a lookup table indexing methods by their name including parameters signature.
let lookup = Methods.Where(m => !m.IsConstructor && !m.IsStatic && !m.IsGeneratedByCompiler)
.ToLookup(m1 => m1.Name)
from t in Application.Types
where !t.IsStatic && t.IsClass &&
// Discard classes deriving directly from System.Object
t.DepthOfInheritance > 1
where t.BaseClasses.Any()
// For each methods not overriding any methods (new slot),
// let's check if it hides by name some methods defined in base classes.
from m in t.InstanceMethods
where m.IsNewSlot && !m.IsExplicitInterfaceImpl && !m.IsGeneratedByCompiler
// Notice how lookup is used to quickly retrieve methods with same name as m.
// This makes the query 10 times faster than iterating each base methods to check their name.
let baseMethodsHidden = lookup[m.Name].Where(m1 => m1 != m && t.DeriveFrom(m1.ParentType))
where baseMethodsHidden.Count() > 0
select new {
m,
baseMethodsHidden,
baseClasses = baseMethodsHidden.ParentTypes(),
Debt = 10.ToMinutes().ToDebt(),
Severity = Severity.High
}
//<Expl>
// The *{0}* hides {2?a:several} method{2?:s} declared in *base {2}* instead of *overriding* {2?it:them}.
// This results in a lack of *polymorphic* behavior at runtime and leads to confusion.
//</Expl>
//<Desc>
// Method hiding: a base class defines non-virtual *M()* and a derived class
// also defines *M()* with the same signature, so *base.M()* and
// *derived.M()* behave differently — not *polymorphism*, where both invoke
// the same implementation on a *derived* instance. This leads to confusion;
// this rule warns about all such cases.
//</Desc>
//<HowToFix>
// Remove or rename the method, or change its parameter signature so it no
// longer hides the base method. Legitimate hiding (same name, different
// behavior) is very rare, see:
// https://learn.microsoft.com/en-us/archive/blogs/ericlippert/method-hiding-apologia
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Object Oriented Design: all 14 items
- Avoid interfaces too big ND1200
- Base class should not use derivatives ND1201
- Class shouldn't be too deep in inheritance tree ND1202
- Class with no descendant should be sealed if possible ND1203
- Overrides of Method() should call base.Method() ND1204
- Do not hide base class methods ND1205
- A stateless class or structure might be turned into a static type ND1206
- Non-static classes should be instantiated or turned to static ND1207
- Methods should be declared static if possible ND1208
- Constructor should not call a virtual method ND1209
- Avoid the Singleton pattern ND1210
- Don't assign static fields from instance methods ND1211
- Avoid empty interfaces ND1212
- Avoid types initialization cycles ND1213