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.