0

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.

Konamiman
  • 49,681
  • 17
  • 108
  • 138
Anima
  • 339
  • 2
  • 16
  • 2
    Not out-of-the-box, not without trying to inject code into your application , or without specifically boiler-plating the functionality – TheGeneral Oct 31 '18 at 07:49
  • Having said this your question is quite broad, unless yiu show what you´ve tried already. You´ll need some framework that calls the methods annotaed with the attribute. There´s no way for your program to guess what those attributes mean. – MakePeaceGreatAgain Oct 31 '18 at 07:49
  • Yes.. It is possible... You need to create your own class which inherits from the `Attribute` class and write your logic over there... For the example you shared, The code in TestMethod attribute checks if there are any method with TestInitialize attribute and execute them before current method and after that it checks for method with TestCleanup attribute and execute them. This requires heavy use of Reflection. – Chetan Oct 31 '18 at 07:50
  • You can have a look at the NUnit source code https://github.com/nunit to understand how it works there. – Chetan Oct 31 '18 at 07:51
  • 1
    This is the link to the similar question. [Aspect Oriented Programming in .NET](https://stackoverflow.com/questions/46000757/net-core-attributes-that-execute-before-and-after-method) – CodeConstruct Oct 31 '18 at 07:58

3 Answers3

2

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...
Marius Bancila
  • 16,053
  • 9
  • 49
  • 91
  • Thank you for the great explenation. Is there a possibility to get around the Executor class being called? Could I get the Init taggeg function to be called when I call a Function tagged with Run? So when I put in the main class example.Run() that example.Init() and InitMore() are called? – Anima Oct 31 '18 at 10:46
  • Not in this approach based on Reflection. You could use the template method pattern as shown below in the other answer, although that is not as flexible as this. – Marius Bancila Oct 31 '18 at 13:04
  • This is how the unit test executor is working itself. – Sebastian 506563 Oct 31 '18 at 14:01
0

What you are looking for is called Aspect Oriented Programming and unfortunately (or not, depends on who you ask) C# doesn't implement any native mechanism to support it. Implementing an AOP engine is certainly possible but not trivial, you'll need to use some kind of dynamic proxy (related questions: .NET Core: attributes that execute before and after method as pointed by CodeConstruct and How to make a simple dynamic proxy in C#; also here's a nice article about the subject).

Konamiman
  • 49,681
  • 17
  • 108
  • 138
0

There's a couple of alternative solutions.

For one, you could use Template Methods where the initialization and cleanup are defined in a base class, and your implementing class only implements the DoWorkImpl method. Calling DoWork would call Initialize, then run the DoWorkImpl method which is implemented in the inheriting class and finish off with Cleanup. This would look something like this in (pseudo) code:

public abstract class BaseClass
{
    public void DoWork()
    {
        Initialize();
        DoWorkImpl();
        CleanUp();
    }

    public abstract void DoWorkImpl();

    private void Initialize()
    {
       // Initialization code here.
    }

    private void Cleanup()
    {
       // Cleanup code here.
    }
}

Another alternative is to use Actions.
This would look something like this in (pseudo) code:

public void SurroundWithInitializeAndCleanup(Action actionToWrap)
{
    Initialize();
    actionToWrap();
    Cleanup();
}

private void Initialize()
{
    // Initialization code here.
}

private void Cleanup()
{
   // Cleanup code here.
}
rickvdbosch
  • 14,105
  • 2
  • 40
  • 53