You may have situations where you are looking to implement an aspect as part of a larger pattern. Perhaps you want to add an aspect, implement an interface and dynamically inject some logic into the target code. In those situations, you will want to apply an aspect to the target code and have that aspect then add other aspects to other elements of code.
The theoretical concept can cause some mental gymnastics, so let's take a look at the implementation.
Create an aspect that implements that IAspectProvider interface.
public class ProviderAspect : IAspectProvider { public IEnumerable<AspectInstance> ProvideAspects(object targetElement) { throw new System.NotImplementedException(); } }
Cast the target object parameter to the type that will be targeted by this aspect:
Assembly
,Type
,MethodInfo
,ConstructorInfo
orLocationInfo
.public IEnumerable<AspectInstance> ProvideAspects(object targetElement) { Type type = (Type) targetElement; throw new NotImplementedException(); }
The ProvideAspects(object) method returns an AspectInstance of the aspect type you want, for every target element of code.
public IEnumerable<AspectInstance> ProvideAspects(object targetElement) { Type type = (Type)targetElement; return type.GetMethods().Select( m => new AspectInstance(m, new LoggingAspect() ) ); }
This aspect will now add aspects dynamically at compile time. Use of the IAspectProvider interface and technique is usually reserved for situations where you are trying to implement a larger design pattern. For example, it would be used when implementing an aspect that created the NotifyPropertyChangedAttribute pattern across a large number of locations in your codebase. It is overkill for many of the situations that you will encounter. Use it only for complicated pattern implementation aspects that you will create.
Note
To read more about NotifyPropertyChangedAttribute, see Handling Corner Cases of the NotifyPropertyChanged Aspect.
Note
PostSharp does not automatically initialize the aspects provided by IAspectProvider, even if the method CompileTimeInitialize
is defined. Any initialization, if necessary, should be done in the ProvideAspects
method or in the constructor of provided aspects.
However, these aspects are initialized at run time just like normal aspects using the RunTimeInitialize
method.
Creating Graphs of Aspects
It is common that aspects provided by IAspectProvider (children aspects) form a complex object graph. For instance, children aspects may contain a reference to the parent aspect.
An interesting feature of PostSharp is that object graphs instantiated at compile-time are serialized, and can be used at run-time. In other words, if you store a reference to another aspect in a child aspect, you will be able to use this reference at run time.
See Also
Reference
IAspectProvider
NotifyPropertyChangedAttribute
ProvideAspects(object)
AspectInstance
Other Resources
INotifyPropertyChanged
Handling Corner Cases of the NotifyPropertyChanged Aspect