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.