49

As you can see in the code below, the DoStuff() method is getting called before the Init() one during the construction of a Child object.

I'm in a situation where I have numerous child classes. Therefore, repeating a call to the DoStuff() method directly after Init() in the constructor of each child wouldn't be an elegant solution.

Is there any way I could create some kind of post constructor in the parent class that would be executed after the child's constructor? This way, I could call to the DoStuff() method there.

If you have any other design idea which could solve my problem, I'd like to hear it too!

abstract class Parent
{
    public Parent()
    {
        DoStuff();
    }

    protected abstract void DoStuff();
}

class Child : Parent
{
    public Child()
    // DoStuff is called here before Init
    // because of the preconstruction
    {
        Init();
    }

    private void Init()
    {
        // needs to be called before doing stuff
    }

    protected override void DoStuff() 
    {
        // stuff
    }
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
  • Found this link that shows order of construction... http://www.csharp411.com/c-object-initialization/ basically states that your derived instance constructor is last on the list of stuff to do. I think pulling DoStuff out of the base class constructor and explicitely calling it is the most straightforeward approach, or providing a base class Init that can be overridden. – deepee1 Jul 22 '11 at 16:20
  • 1
    +1: I don't know why but I always (incorrectly) assumed the child constructor was called first; which is why I always used :base() in my constructor calls. Thanks for educating me. – NotMe Sep 15 '11 at 15:08

11 Answers11

19

If you have a complex logic for constructing your objects then consider FactoryMethod pattern.

In your case I would implement it as a simple

public static Parent Construct(someParam)

method that takes some parameter and based on it decides which child class to instantiate. You can remove your DoStuff() method call from the constructor and call it inside Construct() on the new instance.

Also, you should avoid virtual/abstract method calls in the constructors. See this question for more details: Virtual member call in a constructor

Community
  • 1
  • 1
Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
14

Let me introduce a general solution using some C# features. Note that this solution does not require you to use a factory pattern or invoke anything after constructing the object, and it works on any class with just implementing an interface with a single method. First we declare an interface that our classes will have to implement:

public interface IInitialize {
    void OnInitialize();
}

Next we add a static extension class for this interface, and add the Initialize method:

public static class InitializeExtensions
{
    public static void Initialize<T>(this T obj) where T: IInitialize
    {
        if (obj.GetType() == typeof(T))    
            obj.OnInitialize();
    }
}

Now, if we need a class and all of its descendants to call an initializer right after the object is fully constructed, all we need to do is implement IInitialize and append a line in the constructor:

public class Parent : IInitialize
{
    public virtual void OnInitialize()
    {
        Console.WriteLine("Parent");
    }

    public Parent()
    {
        this.Initialize();
    }
}

public class Child : Parent
{
    public Child()
    {
        this.Initialize();
    }

    public override void OnInitialize()
    {
        Console.WriteLine("Child");
    }
}

public class GrandChild : Child
{
    public GrandChild()
    {
        this.Initialize();
    }

    public override void OnInitialize()
    {
        Console.WriteLine("GrandChild");
    }
}

The trick is that when a derived class calls the extension method Initialize, that will suppress any calls not made from the actual class.

Márton Balassa
  • 818
  • 7
  • 11
  • Except for the fact that every derived class needs to call Initialize() at the end of the constructor, this is close to perfect for me! Though I wish they added an attribute for a method to be called after initialization – Guiorgy Aug 19 '20 at 14:05
  • 2
    This is the closer you can get to what you need. The CLR has no means of running a method automatically after the constructor. However you can still create a static factory that calls Initialize for you (and get rid of the Initialize calls in the constructors): – Márton Balassa Feb 10 '21 at 11:29
  • Thanks for your help, I simplified you solution using generic method like : public void PostConstructor() { // check if (GetType() != typeof(T)) return; // one time initialization } Then call PostConstuctor() from constructor. – Adam Maixner Jul 10 '22 at 08:28
11

How about this:

abstract class Parent
{
    public Parent()
    {
        Init();
        DoStuff();
    }

    protected abstract void DoStuff();
    protected abstract void Init();
}

class Child : Parent
{
    public Child()
    {
    }

    protected override void Init()
    {
        // needs to be called before doing stuff
    }

    protected override void DoStuff() 
    {
        // stuff
    }
}
taylonr
  • 10,732
  • 5
  • 37
  • 66
  • I'd argue calling `Init()` before Parent's `DoStuff` in Child's `DoStuff` is the better option, so that the base class remains unaware of the need to perform initialization operations (unless, of course, ALL subclasses end up requiring it...) – Dan J Jul 22 '11 at 16:27
  • But parent's DoStuff is abstract, there isn't actually a method there. Both DoStuff and Init are on the Child. I agree though, if some children don't need to call Init then this solution becomes troublesome. – taylonr Jul 22 '11 at 17:37
  • 3
    -1 Do not you see that class hierarchy and constructor initialization itself covers both DoStuff() and Init() in current implementation? It's useless pieces of junky code in this case – Alan Turing Jul 22 '11 at 18:02
  • I did see that, but he said the order was out of whack. Therefore, my solution forces the order to be init and then DoStuff. The nice part about this solution is if you soon realize that init and/or dostuff is the same for all children, you just implement it in the base class and your code is instantly better – taylonr Jul 25 '11 at 12:49
  • 7
    What if Child's Init() method implementation depends on arguments passed to Child's constructor? – ygormutti Aug 12 '15 at 19:05
  • 7
    Call abstract/virtual method inside constructor may cause unexpected behavior/bug, the **Factory** approach below is better IMO [Virtual member call in a constructor](http://stackoverflow.com/questions/119506/virtual-member-call-in-a-constructor) – Tr1et Nov 12 '16 at 04:16
  • 3
    This answer does not solve the problem, it even creates more problems. The child's `Init` method assumes that the Child is fully constructed, but that will not be the case. Everything in `Child` will be uninitialized when `Init` and `DoStuff`are called. See my answer here for a working solution: https://stackoverflow.com/a/38659627/5119450 – Márton Balassa Sep 10 '17 at 11:20
6

As others have mentioned, you should use a Factory Pattern.

public class Parent
{
    public Parent()
    {            
    }

    public virtual void PostConstructor()
    {
    }
}

public class Child : Parent
{
    public override void PostConstructor()
    {
        base.PostConstructor();

        // Your code here
    }
}

public void FactoryMethod<T>() where T : Parent
{
    T newobject = new T();
    newobject.PostConstructor();
}
Nic Foster
  • 2,864
  • 1
  • 27
  • 45
3

I would strongly suggest use Factory like a pattern.

If it's possible:

1. Push all your childs and abstract class into separate assembly.

2. Declare ctors of childs like internal methods, so no one out of that assembly is can construct them just by calling ctor.

3. Implement the Factory class to construct for caller specified objects type, which obviuoly will forse calling of abstract DoStuff() method after actual creation of anobject, but before returning it to caller.

Good thing about this is that: It will give you also additional level of abstraction, so if in the future you will need some more functions call or any other type of logical complexity, what you will need, is just add them into your Factory class.

That is.

Regards

Tigran
  • 61,654
  • 8
  • 86
  • 123
  • Idea for when separate assembly isn't possible: for DEBUG builds, have a method in the base ctor look at the stack and make sure it was called by the factory method. – Jared Thirsk Nov 29 '13 at 02:36
  • Another alternate idea: move child classes to it's own namespace, perhaps with a name such as MyNamespace.DoNotUseThisUseFactoryMethodInstead, so you don't using ...; it and use child ctor's by accident. – Jared Thirsk Nov 29 '13 at 02:40
2

In WPF applications, you can postpone the invokation of DoStuff() with the help of Dispatcher:

abstract class Parent
{
    public Parent()
    {
        Dispatcher.CurrentDispatcher.BeginInvoke(new Action(this.DoStuff));
    }

    private void DoStuff()
    {
        // stuff, could also be abstract or virtual
    }
}

However, it is not guaranteed that DoStuff() will be called immediately after the constructor.

hillin
  • 1,603
  • 15
  • 21
1

Correction: As per this answer, you can't determine when the base class's constructor is invoked during construction of the subclass.

E.g. This doesn't work:

public Child()
// DoStuff is called here after Init
// because of the overridden default constructor
{
    Init();
    base();
} 

So, yes, as others have noted, if sequence of events matters, then the base class needs to be able to accommodate that by declaring abstract methods in order, or (better yet) by having the child class's implementation of DoStuff represent the sequence of events:

protected override void DoStuff()
{
    Init();
    base.DoStuff();
}
Community
  • 1
  • 1
Dan J
  • 16,319
  • 7
  • 50
  • 82
1

DoStuff is abstract. Just call Init from the top of DoStuff.

hoodaticus
  • 3,772
  • 1
  • 18
  • 28
  • For my scenario, Init() would need to be called in the DoStuff() override of each child, which isn't better than putting DoStuff() in the constructor of each child. Also, Init() could possibly be needed for other methods, therefore it needs to be done somewhere in the construction. –  Jul 22 '11 at 16:21
  • 1
    That makes taylonr's solution much more viable. – Dan J Jul 22 '11 at 16:39
0
    class MyBase
    {
        public MyBase()
        {
            //... do something

            // finally call post constructor                
            PostConstructor<MyBase>();
        }

        public void PostConstructor<T>(  )
        {
            // check
            if (GetType() != typeof(T))
                return;

            // info
            System.Diagnostics.Debug.WriteLine("Post constructor : " + GetType());
        }
    }

    class MyChild : MyBase
    {
        public MyChild()
        {
            // ... do something

            // ... call post constructor
            PostConstructor<MyChild>();
        }
    }
0

How about...

public MyClass()
{
    Dispatcher.UIThread.Post(RunAfterConstructor);
}

I also tried with Task.Run but that didn't work reliably.

Etienne Charland
  • 3,424
  • 5
  • 28
  • 58
-1

Rather than using an abstract method, which would require you to implement the method in all descendant classes, you might try:

public class Parent
{
    public Parent()
    {
        PostConstructor();
    }


    protected virtual void PostConstructor()
    {
    }
}

public class Child : Parent
{
    protected override void PostConstructor()
    {
        base.PostConstructor();

        /// do whatever initialization here that you require
    }
}

public class ChildWithoutOverride
{
    /// not necessary to override PostConstructor 
}
3Dave
  • 28,657
  • 18
  • 88
  • 151
  • @Artur ? That is pretty simple. – 3Dave Jul 22 '11 at 17:51
  • Yes +1 for elegance, i am an apologet of K.I.S.S. otherwise even tiny frameworks can easily become monstrous. – Alan Turing Jul 22 '11 at 17:58
  • Ups... if someone prefer abstractionism... i advice them to remember such things make notes, which is better, or at least create compiler warnings meta attribute to mark a base class or/and method to track Init() implementations in child classes rather than affect all class hierarchy complexidy and make a complex and dirty code – Alan Turing Jul 22 '11 at 18:15
  • 12
    -1 This does not solve the problem and is misleading - `PostConstructor()` will actually be called before the child constructor. Using empty virtual methods instead of abstract in the solution posted by @taylonr would be the better solution if you don't need to implement `Init()` and `DoStuff()` in all child classes. – Paul Haley Dec 09 '11 at 13:34
  • @DavidLively At `PostConstructor()` we'll be able to use `this`? – cvsguimaraes May 10 '13 at 12:08