Constructor should not call a virtual method
Matches constructors of a non-sealed class calling virtual methods.
Constructors run base-first, but virtual calls always execute on the most derived type. A virtual call in a constructor may thus run on a class whose constructor hasn't executed yet — an unsuitable state — making the class error-prone to derive from.
Constructors run base-first, but virtual calls always execute on the most derived type. A virtual call in a constructor may thus run on a class whose constructor hasn't executed yet — an unsuitable state — making the class error-prone to derive from.
How to fix
Re-design object initialization or declare the class sealed if possible. A constructor should initialize its own class's state; extra setup belongs in derived constructors or methods called after construction.
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>Constructor should not call a virtual method</Name>
// <Id>ND1209:ConstructorShouldNotCallAVirtualMethod</Id>
warnif count > 0
from t in JustMyCode.Types where
t.IsClass &&
!t.IsGeneratedByCompiler &&
!t.IsSealed
from ctor in t.Constructors
let virtualMethodsCalled =
from mCalled in ctor.MethodsCalled
where mCalled.IsVirtual && !mCalled.IsFinal &&
// Only take care of just-my-code virtual methods called
JustMyCode.Contains(mCalled) &&
( mCalled.ParentType == t ||
(t.DeriveFrom(mCalled.ParentType) &&
// Don't accept Object methods since they can be called
// from another reference than the 'this' reference.
mCalled.ParentType.FullName != "System.Object")
)
select mCalled
where virtualMethodsCalled.Count() > 0
select new {
ctor ,
virtualMethodsCalled,
// If there is no derived type, it might be
// an opportunity to mark t as sealed.
t.DerivedTypes,
Debt = ((virtualMethodsCalled.Count())*4).ToMinutes().ToDebt(),
Severity = Severity.High
}
//<Expl>
// The *{0}* should not call the *virtual {1}* because doing so
// can potentially corrupt the object initialization process.
//</Expl>
//<Desc>
// Matches constructors of a non-sealed class calling virtual methods.
//
// Constructors run base-first, but virtual calls always execute on the most
// derived type. A virtual call in a constructor may thus run on a class
// whose constructor hasn't executed yet — an unsuitable state — making the
// class *error-prone* to derive from.
//</Desc>
//<HowToFix>
// Re-design object initialization or declare the class *sealed* if possible.
// A constructor should initialize its own class's state; extra setup belongs
// in derived constructors or methods called after construction.
//</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