Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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     } } 
like image 417
Robin King Avatar asked Nov 03 '11 17:11

Robin King


People also ask

Which constructor is called automatically?

Static constructors are called automatically, immediately before any static fields are accessed, and are generally used to initialize static class members.

Does base class constructor get called automatically?

If a base class has a default constructor, i.e., a constructor with no arguments, then that constructor is automatically called when a derived class is instantiated if the derived class has its own default constructor.

Can constructors call methods?

A constructor can call methods, yes. A method can only call a constructor in the same way anything else can: by creating a new instance. Be aware that if a method constructs a new object of the same type, then calling that method from a constructor may result in an infinite loop...

How do you call a constructor a second time?

It's not possible to call the constructor two times without using reflection as it's called only once to construct the object. Instance constructors are used to create and initialize any instance member variables when you use the new expression to create an object of a class.


2 Answers

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(); 
like image 109
Jeremy Todd Avatar answered Sep 20 '22 14:09

Jeremy Todd


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.

like image 20
Márton Balassa Avatar answered Sep 20 '22 14:09

Márton Balassa