Search code examples
c#.netfunctioncallimplicit

Call a function implicitly after a function is called


Is it possible to implement such a behaviour like it is used in Unit-Tests where you cann anotate with

[TestInitialize]

to execute this function everytime before a

[TestMethod]

is executed. And in the same way

[TestCleanup]

is always executed after the TestMethod.


Solution

  • You cannot do this out of the box. You need to write your own execution code that uses reflection to figure out what and how to execute. Below, I will share a simple example.

    First, you need the attributes to describe the type of methods.

    class InitMethodAttribute : Attribute
    {
       public InitMethodAttribute():base()
       { }
    };
    
    class CleanupMethodAttribute : Attribute
    {
       public CleanupMethodAttribute() : base()
       { }
    };
    
    class RunMethodAttribute : Attribute
    {
       public RunMethodAttribute() : base()
       { }
    };
    

    We'll use this on an example class. Notice that all the methods in this example are private. They can be invoked through reflection. Also, notice that for simplicity they do not have parameters and don't return anything. You can work around this example and change it to support parameters too.

    class Example
    {
       [InitMethod]
       private void Init()
       {
          Console.WriteLine("Initializing...");
       }
    
       [InitMethod]
       private void InitMore()
       {
          Console.WriteLine("More initializing...");
       }
    
       [RunMethod]
       private void Run()
       {
          Console.WriteLine("Running...");
       }
    
       [CleanupMethod]
       private void Cleanup()
       {
          Console.WriteLine("Cleaning up...");
       }
    }
    

    The next class, called executor, takes an object and looks at its type, identifying methods and looking at their attributes. Eventually, if the RunMethod attribute is found on any method, the method is executed. Before it are executed all the InitMethod decorated methods and after it all the CleanupMethod decorated methods.

       static class Executor
       {
          public static void Run(object obj)
          {
             var type = obj.GetType();
             var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
    
             var initMethods = new List<MethodInfo>();
             var cleanMethods = new List<MethodInfo>();
             foreach (var method in methods)
             {
                var initattrs = method.GetCustomAttributes(typeof(InitMethodAttribute));
                var cleanattrs = method.GetCustomAttributes(typeof(CleanupMethodAttribute));
    
                if (initattrs != null && initattrs.Count() > 0)
                   initMethods.Add(method);
                else if (cleanattrs != null && cleanattrs.Count() > 0)
                   cleanMethods.Add(method);
             }
    
             foreach (var method in methods)
             {
                var runattrs = method.GetCustomAttributes(typeof(RunMethodAttribute));
                if(runattrs != null)
                {
                   var runattr = runattrs.FirstOrDefault();
                   if(runattr != null)
                   {
                      foreach (var m in initMethods)
                         m.Invoke(obj, null);
    
                      method.Invoke(obj, null);
    
                      foreach (var m in cleanMethods)
                         m.Invoke(obj, null);
                   }
                }
             }
          }
       }
    

    The following program uses all this:

    class Program
    {
       static void Main(string[] args)
       {
          var example = new Example();
          Executor.Run(example);
       }
    }
    

    The output is:

    Initializing...
    More initializing...
    Running...
    Cleaning up...