Tar
Tar

Reputation: 9015

How to apply aspect dynamically?

I have this clas:

[NotifyPropertyChangedAspect] // my own aspect implementation...
class Foo {
    [OnSetAspect("OnSetExamplaryProperty")] // my own aspect implementation as well...
    public int ExamplaryProperty { get; set; }
    void OnSetExamplaryProperty() { /* do stuff... */ }

    public bool Condition { get; set; }

    [DependsOnAspect("Condition")]
    public bool Dependent { get; set; }
}

Whenever Condition changes, I want to fire the PropertyChanged with PropertyName == "Dependent" as well. I know I can do it vice versa (apply the aspect on Condition with its dependent properties, or just add a PropertyChanged handler in the constructor), but I want it this way :-)

So here are the possible solutions I could think of:

  1. Somehow inject my own OnSetAspect during compilation (override CompileTimeInitialize? using Emit?)
  2. Somehow inject my own OnSetAspect during runtime (again, how?)
  3. Apply my own OnSetAspect using IAspectProvider (I'm guessing here... not really sure about feasibility and/or implementation simplicity)

So how do I fill up my DependsOnAspect class body to achieve my goal?

[Serializable]
public class DependsOnAspect : LocationInterceptionAspect {
    /* what goes here? */
}

What's the simplest solution?

Upvotes: 0

Views: 122

Answers (1)

Daniel Balas
Daniel Balas

Reputation: 1850

In my opinion, you should intercept set_Condition and fire the PropertyChanged event here. So the DependsOnAspect doesn't really need to be an aspect (you do not need to transform Dependent because it has the attribute on it property) - just a regular attribute.

The outline would be: NotifyPropertyChangedAspect will provide OnMethodBoundaryAspects (it will implement IAspectProvider) to all property setters and analyze all properties for [DependsOn] attributes (at build time). In runtime each property setter aspect will fire PropertyChangedEvent for all properties that had [DependsOn] attribute pointing to the particular property.

public class DependsOnAttribute : Attribute { ... }

[PSerializable]
[IntroduceInterface(typeof(INotifyPropertyChanged))]
public class NotifyPropertyChangedAspect : InstanceLevelAspect, IAspectProvider, INotifyPropertyChanged
{
    IEnumerable<AspectInstance> IAspectProvider.ProvideAspects(object targetElement)
    {
        // targetElement is Type, go through it's properties and provide SetterInterceptionAspect to them
    }

    public override void CompileTimeInitialize( Type type, AspectInfo aspectInfo )
    {
        // scan for [DependsOn] here
    }

    [PSerializable]
    public class SetterInterceptionAspect : OnMethodBoundaryAspect
    {
        // ...
        public override void OnExit(MethodExecutionArgs args)
        {
            // fire PropertyChanged event here
        }
        // ...
    }
    // ...
}

You would need to tinker with it a little bit, but I hope that this will be usable as an outline.

Upvotes: 1

Related Questions