Virtual Member Call in a Constructor

Virtual member call in a constructor

When an object written in C# is constructed, what happens is that the initializers run in order from the most derived class to the base class, and then constructors run in order from the base class to the most derived class (see Eric Lippert's blog for details as to why this is).

Also in .NET objects do not change type as they are constructed, but start out as the most derived type, with the method table being for the most derived type. This means that virtual method calls always run on the most derived type.

When you combine these two facts you are left with the problem that if you make a virtual method call in a constructor, and it is not the most derived type in its inheritance hierarchy, that it will be called on a class whose constructor has not been run, and therefore may not be in a suitable state to have that method called.

This problem is, of course, mitigated if you mark your class as sealed to ensure that it is the most derived type in the inheritance hierarchy - in which case it is perfectly safe to call the virtual method.

Solving virtual member call in constructor

You don't. You accept the fact this is dangerous, and (try to) prevent this. This is a design flaw!

You could prevent this for example by moving the call to the highest level class, or make every class responsible for it's own, thus removing the unsafe part of the method call. Then you don't need another class (a base class) to take responsibility for its deriving classes.

If that isn't possible. Make very clear using comments or any other method available that the developer should take this problem into account when updating the code.

Solving the 'Virtual method call in constructor' issue

I've encountered this issue quite a few times and the best way I've found to properly resolve it is to abstract the virtual method that is being called from the constructor, into a separate class. You would then pass an instance of this new class into the constructor of your original abstract class, with each derived class passing it's own version to the base constructor. It's a bit tricky to explain so I'll give an example, based on yours.

public abstract class Instruction
{
protected Instruction(InstructionSet instructionSet, ExpressionElement argument, RealInstructionGetter realInstructionGetter)
{
if (realInstructionGetter != null)
{
RealInstruction = realInstructionGetter.GetRealInstruction(instructionSet, argument);
}
}

public Instruction RealInstruction { get; set; }

// Abstracted what used to be the virtual method, into it's own class that itself can be inherited from.
// When doing this I often make them inner/nested classes as they're not usually relevant to any other classes.
// There's nothing stopping you from making this a standalone class of it's own though.
protected abstract class RealInstructionGetter
{
public abstract Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument);
}
}

// A sample derived Instruction class
public class FooInstruction : Instruction
{
// Passes a concrete instance of a RealInstructorGetter class
public FooInstruction(InstructionSet instructionSet, ExpressionElement argument)
: base(instructionSet, argument, new FooInstructionGetter())
{
}

// Inherits from the nested base class we created above.
private class FooInstructionGetter : RealInstructionGetter
{
public override Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument)
{
// Returns a specific real instruction
return new FooRealInstuction(instructionSet, argument);
}
}
}

// Another sample derived Instruction classs showing how you effictively "override" the RealInstruction that is passed to the base class.
public class BarInstruction : Instruction
{
public BarInstruction(InstructionSet instructionSet, ExpressionElement argument)
: base(instructionSet, argument, new BarInstructionGetter())
{
}

private class BarInstructionGetter : RealInstructionGetter
{
public override Instruction GetRealInstruction(InstructionSet instructionSet, ExpressionElement argument)
{
// We return a different real instruction this time.
return new BarRealInstuction(instructionSet, argument);
}
}
}

In your particular example it does get a little confusing and I started to run out of sensible names, but this is due to the fact you already have a nesting of Instructions within Instructions, i.e. an Instruction has a RealInstruction (or at least optionally does); but as you can see it is still possible to achieve what you want and avoid any virtual member calls from a constructor.

In case that's still not clear, I'll also give an example based on one I used just recently in my own code. In this case I have 2 types of forms, a header form and a message form, both of which inherit from a base form. All forms have fields but each form type has a different mechanism for constructing its fields, so I originally had an abstract method called GetOrderedFields that I called from the base constructor and the method was overriden in each derived form class. This gave me the resharper warning you mention. My solution was the same pattern as above and is as follows

internal abstract class FormInfo
{
private readonly TmwFormFieldInfo[] _orderedFields;

protected FormInfo(OrderedFieldReader fieldReader)
{
_orderedFields = fieldReader.GetOrderedFields(formType);
}

protected abstract class OrderedFieldReader
{
public abstract TmwFormFieldInfo[] GetOrderedFields(Type formType);
}
}

internal sealed class HeaderFormInfo : FormInfo
{
public HeaderFormInfo()
: base(new OrderedHeaderFieldReader())
{
}

private sealed class OrderedHeaderFieldReader : OrderedFieldReader
{
public override TmwFormFieldInfo[] GetOrderedFields(Type formType)
{
// Return the header fields
}
}
}

internal class MessageFormInfo : FormInfo
{
public MessageFormInfo()
: base(new OrderedMessageFieldReader())
{
}

private sealed class OrderedMessageFieldReader : OrderedFieldReader
{
public override TmwFormFieldInfo[] GetOrderedFields(Type formType)
{
// Return the message fields
}
}
}

Virtual Member in Constructor, workaround

[10.11] of the C# Specification tells us that object constructors run in order from the base class first, to the most inherited class last. Whereas [10.6.3] of the specification tells us that it is the most derived implementation of a virtual member which is executed at run-time.

What this means is that you may receive a Null Reference Exception when attempting to run a derived method from the base object constructor if it accesses items that are initialized by the derived class, as the derived object has not had it's constructor run yet.

Effectively, the Base method's constructor runs [10.11] and tries to reference the derived method CreateSubject() before the constructor is finished and the derived constructor can be run, making the method questionable.

As has been mentioned, in this case, the derived method seems to only rely upon items passed as parameters, and may well run without issue.

Note that this is a warning, and is not an error per se, but an indication that an error could occur at runtime.

This would not be a problem if the methods were called from any other context except for the base class constructor.

virtual member call in constructor c#

This could be an alternative way:

public abstract class ClassA
{
private int m_number;
protected ClassA(int n)
{
m_number = n;
}

//protected abstract int GetNumber();
}

public class ClassB : ClassA
{
public ClassB() : base(10)
{
}

//protected override int GetNumber()
//{
// return 10;
//}
}

Virtual member call in a constructor when assigning value to property

It's because your Message property can be overridden by class ChildClass : DerivedClass - at which point it's possible to invoke code in Message on ChildClass from the ctor in DerivedClass, and your ChildClass instance may not be full initialised.

That's why making your DerivedClass sealed solves the problem - it cannot be inherited.

Virtual member call in constructor

A virtual member call in the base class ctor could cause some logic to run in the subclass before the subclass' ctor is called (and thus before the object gets a chance to initialize itself to a consistent state).

It's just a nice reminder so you know you are doing something that could potentially cause some nasty unexpected behavior.

Virtual member call in constructor, sealed, and attributes

If all you are doing in B's constructor is setting a default value for Foo, just use a property with a backing field and set the default value in the field initializer:

public class B : A
{
private string foo = "test";

[Bar(1, 2)]
public override string Foo
{
get { return foo; }
set { foo = value; }
}
}

Calling virtual functions inside constructors

Calling virtual functions from a constructor or destructor is dangerous and should be avoided whenever possible. All C++ implementations should call the version of the function defined at the level of the hierarchy in the current constructor and no further.

The C++ FAQ Lite covers this in section 23.7 in pretty good detail. I suggest reading that (and the rest of the FAQ) for a followup.

Excerpt:

[...] In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn’t yet happened. Objects are constructed from the base up, “base before derived”.

[...]

Destruction is done “derived class before base class”, so virtual functions behave as in constructors: Only the local definitions are used – and no calls are made to overriding functions to avoid touching the (now destroyed) derived class part of the object.

EDIT Corrected Most to All (thanks litb)



Related Topics



Leave a reply



Submit