0

I had the thought that it'd be nice to move logging details outside of a method if it were possible. My first thought was to wonder if this could be done through annotations or attributes. For example

[LogBeforeRunning("Foo is about to be run.")]
[LogAfterRunning("Foo has been run.")]
[LogOnError("Foo ran into some errors while running.")]
public void Foo() 
{
    //do something
}

I know the ASP.NET MVC framework has something like this, but I don't know how much wiring this would take to setup. Another question worth asking is would this even be of value? I think it would, but the logging wouldn't have pertinent variable information so I would still need more details than this.

Still, how would one go about something like this? I'm curious to know if it is possible.

jason
  • 2,219
  • 5
  • 33
  • 66

1 Answers1

0

No it's not what attributes are made for. They are evaluated when the assembly is loaded and you cannot know when this happens. It is relatively unreliable. An assembly may be loaded way ahead of it's time (even at program start) or not (lazy loading). Even loading order may be unpredictable when there are no references between them.

Best is not to rely on assembly loading time and order at all. For AOP there is no current language construct, but there may be extensions you can use.

What I have done in a similar case was implement an execution pattern like this:

public static class AOP
{
    public static void Execute(Action f)
    {
        // check if f has a LogBeforeRunning attribute and log the text
        try
        {
            f();
        }
        catch
        {
            // check if f has a LogOnError attribute and log the text
        }
        // check if f has a LogAfterRunning attribute and log the text
    }

    public static void Execute<T>(Action<T> f, T arg)
    {
        // check if f has a LogBeforeRunning attribute and log the text
        try
        {
            f(arg);
        }
        catch
        {
            // check if f has a LogOnError attribute and log the text
        }
        // check if f has a LogAfterRunning attribute and log the text
    }

    public static void Execute<T1, T2>(Action<T1, T2> f, T1 arg1, T2 arg2)
    {
        // check if f has a LogBeforeRunning attribute and log the text
        try
        {
            f(arg1, arg2);
        }
        catch
        {
            // check if f has a LogOnError attribute and log the text
        }
        // check if f has a LogAfterRunning attribute and log the text
    }

    // more Execute() methods for arity 3, 4, 5, ...
}

Sadly, there is no arbitrary arity generic, so you have to define an Execute() method for each arity (0, 1, 2, 3, ..., 9 arguments).

You would then run

f(1, 2, 3, 4);

this way:

AOP.Execute(f, 1, 2, 3, 4);

I know it's ugly but it works.

pid
  • 11,472
  • 6
  • 34
  • 63