简体   繁体   中英

How do i change the call order of nested constructors (child before abstract parent)

The code below throws an exception because the abstract constructor is called before the child constructor.

I need to provide an abstract class to capsule some logic from a different part of the program. However i also need to check if the abstract members are initialised correctly rigth after creation without the childclass having any influence over this.

the compiling example below should illustrate my question.

using System;

namespace Stackoverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = new Thing(5);
            var y = new Child(x);
        }
    }

    class Child : AbstractParent
    {
        Thing childthing;

        public Child(Thing provided) : base(){
            childthing = provided;
        }

        public override void Initialise(){
            //Exception is thrown here - childthing is still null
            parentthing = childthing.Add(1);
        }
    }

    abstract class AbstractParent
    {
        protected Thing parentthing;

        public AbstractParent(){
            Initialise();
            AssertThingyNotNull();
        }

        private void AssertThingyNotNull(){
            if (parentthing == null) throw new Exception("Waaa");
        }

        public abstract void Initialise();

    }

    class Thing
    {
        private int i;

        public Thing(int i){
            this.i = i;
        }

        public Thing Add(int b){
            i += b;
            return new Thing(i);
        }
    }
}

Edit #1:

Is there some way to do this by reflecting into the caller (should be the creator of child rigth?) and then reacting on the end of that call?

Edit #2: Getting the .ctor that creates the child is easy. Manipulating the methods seems something between impossible and a bad idea.

        foreach (StackFrame frame in new StackTrace().GetFrames())
        {
            Console.WriteLine(frame.GetMethod().Name);
        }

You can't, basically. This is why you should avoid calling virtual (or abstract) members from a constructor as far as possible - you could end up with code which is running with an incomplete context. Any variable initializers are executed before the base class constructor is called, but none of the code within the constructor body is.

If you need to perform initialization and only want to do that when the derived class constructor is running, then just call Initialise from the derived class constructor to start with.

You can do something similar to what Microsoft did with InitializeComponent()

then let the children call it whenever it can.

Try this.

Edited = cleaner version.

using System;

namespace ConsoleApplication3
{
class Program
{
    static void Main(string[] args)
    {
        var x = new Thing(5);
        var y = new Child(x);
    }
}

class Child : AbstractParent
{
    public Child(Thing provided)
        : base()
    {
        parentthing = provided;
        base.Initialise();
    }
}

abstract class AbstractParent
{
    protected Thing parentthing;

    public AbstractParent()
    {

    }

    private void AssertThingyNotNull()
    {
        if (parentthing == null) throw new Exception("Waaa");
    }

    public void Initialise()
    {
        AssertThingyNotNull();
    }

}

class Thing
{
    private int i;

    public Thing(int i)
    {
        this.i = i;
    }

    public Thing Add(int b)
    {
        i += b;
        return new Thing(i);
    }
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM