Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply an aspect to only methods that have a specific attribute

Tags:

c#

aop

postsharp

I'm trying to set up a PostSharp aspect RunOutOfProcessAttribute so that it applies to:

  1. all public methods
  2. any method marked with the DoSpecialFunctionAttribute, regardless of member accessibility (public/protected/private/whatever).

So far, my RunOutOfProcessAttribute is defined thusly:

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, TargetMemberAttributes = MulticastAttributes.Public)]
[AttributeUsage(AttributeTargets.Class)]
public class RunOutOfProcessAttribute : MethodInterceptionAspect
{
    public override void OnInvoke(MethodInterceptionArgs args)
    {
        ...
    }
}

The MulticastAttributeUsageAttribute already in place should fulfil criterion 1 above, but I've got no idea how to fulfil criterion 2, without simply duplicating the behaviour of the existing aspect into a new attribute.

How would I get this aspect to apply to any method marked with the DoSpecialFunctionAttribute, regardless of member accessibility (public/protected/private/whatever)?

like image 900
Fabian Tamp Avatar asked Nov 26 '12 04:11

Fabian Tamp


1 Answers

Here's the solution:

  • Target all methods with [MulticastAttributeUsage(MulticastTargets.Method)]
  • Override CompileTimeValidate(MethodBase method). Set up the return values such that CompileTimeValidate returns true on appropriate targets, false on targets to silently ignore, and throws an exception when the user should be alerted that Aspect usage is inappropriate (this is detailed in the PostSharp documentation).

In code:

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method)]
[AttributeUsage(AttributeTargets.Class)]
public class RunOutOfProcessAttribute : MethodInterceptionAspect
{
    protected static bool IsOutOfProcess;

    public override void OnInvoke(MethodInterceptionArgs args)
    {
        ...
    }

    public override bool CompileTimeValidate(MethodBase method)
    {
        if (method.DeclaringType.GetInterface("IDisposable") == null)
            throw new InvalidAnnotationException("Class must implement IDisposable " + method.DeclaringType);

        if (!method.Attributes.HasFlag(MethodAttributes.Public) && //if method is not public
            !MethodMarkedWith(method,typeof(InitializerAttribute))) //method is not initialiser
            return false; //silently ignore.

        return true;
    }
}
like image 122
Fabian Tamp Avatar answered Oct 08 '22 12:10

Fabian Tamp