1

I have base class that contain abstract method.

public abstract class ClassBase : IClassBase
{
    protected ClassBase()
    {
        ////   some code 
    }

    protected ClassBase(XmlNode settings)
          : this()
    {

    }

    protected abstract void Init(XmlNode settings);
}


public class Class_A : ClassBase
{
    public Class_A(XmlNode settings)
          : this(settings)
    {
        Init(settings);
    }

    protected override void Init(XmlNode settings)
    {


    }
}

Is it ok to call the Init method from Class_A constructor ?

I try to do it and its run ok - but when the constructor is running the virtual tables are not ready yet and the abstract method are not ready as far as i know.

Yanshof
  • 9,659
  • 21
  • 95
  • 195
  • 1
    Reffer to this: http://msdn.microsoft.com/en-us/library/ms182331.aspx –  Jul 14 '14 at 06:46
  • Calling `Init` on partially initialized class will be extremely confusing - your current sample (with calling `Init` from constructor of its own class) is easier to read/follow. I.e. author of derived class will have to think/read all sources to figure out if something need to be done in constructor of the class or some magical code will trigger initialization. – Alexei Levenkov Jul 14 '14 at 06:52

1 Answers1

6

It's unclear exactly what code you meant, as the code you've given doesn't compile for a couple of reasons. Most importantly, did you actually mean to call Init from ClassBase rather than from Class_A? If not, it seems pointless making Init abstract. This answer assumes you did meant that.

Is it ok to call the Init method from Class_A constructor ?

It's valid - but it's not usually a good idea.

It's not a matter of the "virtual tables" no being created - that's fine, and it will execute Class_A.Init. An object is created as an instance of its eventual type immediately. The problem is that you're calling a method on the Class_A instance before its constructor has had a chance to execute. That means it may be in an unexpected state - normal preconditions may not hold, for example.

Example

public class Class_A : ClassBase
{
    private readonly string text;

    public Class_A(XmlNode settings, string text)
        : base(settings) // Which calls Init(settings) as per intro paragraph
    { 
        if (text == null)
        {
            throw new ArgumentNullException("text");
        }
        this.text = text;           
    }

    protected override void Init(XmlNode settings)
    {
        // In here, text is still null... even though it can't be in any
        // other method.
    }
}

Just occasionally, it's the least worst solution, but in that case:

  • Really make sure there isn't a better solution
  • Document it very clearly
  • Avoid calling the method from anywhere else, as it's often odd to code an implementation which is appropriate in both "I'm half way through initialization" and "I'm fully initialized" states.
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    +1. VMT remark in question looks like coming from some C++ book, this is one well know difference between C++ and C# where order of initialization is opposite. Check out [Virtual method call in constructpr](http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor) for more info/links. – Alexei Levenkov Jul 14 '14 at 06:56
  • If that is the correct answer, I wonder why Resharper recognizes this as an issue but proposes to make the overriding class or the overridden method `sealed` as a fix. How would that help? – Krumelur Jul 14 '14 at 06:57
  • 1
    @Krumelur: Well, it means that whoever is writing `Init` can make sure they get it right, without worrying about the problem spreading to other subclasses which might override `Init` without being fully aware of the situation. It's not ideal, but it's better than nothing. – Jon Skeet Jul 14 '14 at 06:58
  • Resharper does not recognizes this as an issue :) – Yanshof Jul 14 '14 at 07:02
  • @Yanshof: Yes it does - it gives a warning of "Virtual method call in constructor". – Jon Skeet Jul 14 '14 at 07:15