Search code examples
c#postsharp

aspect multicasting in postsharp


I've a simple aspect:

[System.Serializable()]
[System.AttributeUsage(System.AttributeTargets.Assembly)]
[PostSharp.Extensibility.MulticastAttributeUsage(PostSharp.Extensibility.MulticastTargets.Method)]
public class NullableMethodCallAspect : PostSharp.Aspects.MethodInterceptionAspect
{

    public override void OnInvoke(PostSharp.Aspects.MethodInterceptionArgs args)
    {
        if (args.Instance != null)
            args.Proceed();
    }

}

I've two projects inside my solution: UI and UIAppearanceExtensibility (this is referenced by UI).

In the second one, I declare some interfaces in order for other developers to use them for creating several implementations according those interfaces.

From UI, I declare properties of those interfaces, for example IInterface1.

So, from my UI project (assembly), I need to apply my aspect to every call to IInterface1 objects...

I've tried that, but, it doesn't work:

[assembly: UI.Aspects.NullableMethodCallAspect(
    AttributeTargetAssemblies = "UIAppearanceExtensibility",
    AttributeTargetTypes = "UI.Appearance.Extensibility.Triage.*",
    AttributeTargetMembers = "regex: handle*"
)]

Solution

  • In the shown example the calls to interface members will be intercepted in the UI assembly, but only when they are accessed through the variable of the interface type.

    For example:

    // Interface in UIAppearanceExtensibility 
    public interface IInterface1
    {
        void Method1();
    }
    
    // Class in UI
    public class Class1 : IInterface1
    {
        // ...
    }
    
    // This usage in UI will be intercepted
    IInterface1 i1 = new Class1();
    i1.Method1();
    
    // This usage in UI will not be intercepted
    Class1 c1 = new Class1();
    c1.Method1();
    

    The reason is that the IL code generated by compiler in the second case does not reference IInterface1 and PostSharp is looking for the usages of IInterface1 when applying the aspect.

    In your case it's probably better to apply the aspect to the interfaces in the UIAppearanceExtensibility assembly itself, and set AttributeInheritance property to MulticastInheritance.Strict. The attribute will then be multicast to the classes implementing the interface. This use case is documented in Understanding Aspect Inheritance.

    // In the UIAppearanceExtensibility project
    [assembly: UI.Aspects.NullableMethodCallAspect(
        AttributeInheritance = MulticastInheritance.Strict
        AttributeTargetTypes = "UI.Appearance.Extensibility.Triage.*",
        AttributeTargetMembers = "regex: handle*"
    )]