Search code examples
postsharp

Can I dynamically generate an aspect before another aspect is run?


I will try to phrase this question with as little details as needed, to keep the question brief. Let me know if more details are required.

I have an aspect X on property A which dynamically generates an aspect Y on property B. Property B may be already contain aspects of type Y, and these interact with each other and the generated instance of Y.

I require the instances of Y generated by X, to be present before the non-generated instances of Y are run. Using AspectDependencies I have not been able to make this work. I've place a AspectDependencyPosition.

The aspect dependency I've placed on X is of the form: [AspectTypeDependency(AspectDependencyAction.Order, AspectDependencyPosition.Before, typeof(Y))]

The execution order that I get is: SourceInstanceOfY,X,GeneratedInstanceOfY

While the execution order that I need is: X,SourceInstanceOfY,GeneratedInstanceOfY where the last two may change order.

Is there a way to solve this solution or it not supported by PostSharp?

Thanks, Remy.


Solution

  • By using AspectTypeDependency you specified the ordering between aspects X and Y, but the order for Y instances is still not specified. You can use the ApectPriority property to order individual instances of the Y aspect. You can find the simple example based on your description below:

    class TestClass
    {
        [MyAspectX]
        public int PropertyA { get; set; }
    
        [MyAspectY("from attribute", AspectPriority = 2)]
        public int PropertyB { get; set; }
    }
    
    [Serializable]
    public class MyAspectX : LocationInterceptionAspect, IAspectProvider
    {
        public override void OnGetValue(LocationInterceptionArgs args)
        {
            Console.WriteLine("X OnGetValue");
            base.OnGetValue(args);
        }
    
        public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        {
            yield return new AspectInstance(
                ((LocationInfo) targetElement).DeclaringType.GetProperty("PropertyB"),
                new MyAspectY("from provider") {AspectPriority = 1});
        }
    }
    
    [Serializable]
    public class MyAspectY : LocationInterceptionAspect
    {
        private string tag;
    
        public MyAspectY(string tag)
        {
            this.tag = tag;
        }
    
        public override void OnGetValue(LocationInterceptionArgs args)
        {
            Console.WriteLine("Y OnGetValue " + tag);
            base.OnGetValue(args);
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(new TestClass().PropertyB);
        }
    }