Do Not Call Overridable In Ctor
ID |
csharp.do_not_call_overridable_in_ctor |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
CSharp |
Tags |
constructor, reliability |
Description
Reports constructor bodies that call a virtual, abstract or override method on the enclosing type. Such calls dispatch through the most-derived override before the derived class’s constructor has had a chance to run.
Rationale
In C#, base-class constructors execute before derived-class fields are initialised. If the base constructor calls a virtual member, the runtime dispatches to the most-derived override — which sees the derived class’s fields still at their default values. The result is intermittent `NullReferenceException`s, half-initialised invariants and behaviour that depends on subclass identity.
public class Base
{
public Base()
{
Initialize(); // FLAW — dispatches to Derived.Initialize before _state is set
}
public virtual void Initialize()
{
}
}
public class Derived : Base
{
private string _state = "ready";
public override void Initialize()
{
Console.WriteLine(_state.Length); // NullReferenceException at runtime
}
}
public sealed class Safe
{
public Safe() => Helper(); // OK - sealed class, no override hazard
private void Helper() { }
}
Remediation
Initialise the object’s state directly in the constructor instead of going through a
virtual member. If polymorphic setup is genuinely required, do it after the object is
constructed — either let the caller invoke the method on the fully-built instance, or
mark the helper private/sealed/non-virtual.