Robin King
Robin King

Reputation: 387

Is there a way to automatically call a particular method immediately after all constructors have run?

I want to be able to call a particular method automatically upon construction of a derived object, however I can't think how to do it. The following code illustrates. Another answer recommended OnLoad, but I am doing this for Unity on Mac and OnLoad doesn't appear to be supported by my platform. Any suggestions?

public class Parent {

    public Parent ()
    {
        // A. Stuff to do before child constructor code runs
        DoThisAutomaticallyAfterConstruction();
    }

    public void DoThisAutomaticallyAfterConstruction()
    {
        // C. In this example, this will run after A, before B. I want it to run ABC
    }
}

public class Child : Parent {

    public Child () : base()
    {
        // B. Stuff to do here after parent constructor code runs
    }
}

Upvotes: 24

Views: 17184

Answers (4)

Márton Balassa
Márton Balassa

Reputation: 927

While @Jeremy Todd's (accepted) answer works and is a widely accepted solution to the problem, it has a drawback: not very IoC and serialization friendly, since your class cannot be properly constructed using new. 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.

Upvotes: 6

phoog
phoog

Reputation: 43056

This sounds like a good candidate for a factory. Make all the constructors private or protected, requiring consumers of your code to call the factory method when they want an instance of your object. In the factory method, you use the new operator to create the object, and then call DoThisAutomaticallyAfterConstruction() before returning the object.

EDIT

A factory may be a static method, or you may have a factory object. See, for example, Wikipedia on the abstract factory pattern at http://en.wikipedia.org/wiki/Abstract_factory_pattern, and the documentation for the ADO.NET DbProviderFactories at http://msdn.microsoft.com/en-us/library/wda6c36e.aspx for a real-world implementation.

Upvotes: 4

Jeremy Todd
Jeremy Todd

Reputation: 3289

Unfortunately there's no built-in way to do what you want (it's a fairly-often-requested feature).

One workaround is to implement a factory pattern, where you don't create objects by calling the constructor directly, but instead implement a static method to create them for you. For example:

public class MyClass
{
  public MyClass()
  {
    // Don't call virtual methods here!
  }

  public virtual void Initialize()
  {
    // Do stuff -- but may be overridden by derived classes!
  }
}

then add:

public static MyClass Create()
{
  var result = new MyClass();

  // Safe to call a virtual method here
  result.Initialize();

  // Now you can do any other post-constructor stuff

  return result;
}

and instead of doing

var test = new MyClass();

you can do

var test = MyClass.Create();

Upvotes: 23

JonH
JonH

Reputation: 33163

Based on your example you are accomplishing ACB, you want to accomplish ABC.

In order to run code after the child constructor, you need to make the call after B (the child constructor) you cannot call the code at A (the parent constructor) then you won't accomplish ABC.

Move DoThisAutomaticallyAfterConstruction() at the end of the child class constructor?

Truly a strange question though.

Upvotes: 2

Related Questions