Fabian Tamp
Fabian Tamp

Reputation: 4516

Apply an aspect to only methods that have a specific attribute

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)?

Upvotes: 6

Views: 1699

Answers (1)

Fabian Tamp
Fabian Tamp

Reputation: 4516

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;
    }
}

Upvotes: 6

Related Questions