Question: what do the following features have in common?
Answer: they all pollute business code and require a lot of boilerplate code to implement.
These are implementation patterns and, although it's possible to explain in natural language how to implement them, the conventional object-oriented paradigm does not allow developers to express them formally - which means they must be implemented manually.
This is precisely why aspect-oriented programming was invented.
PostSharp is the most comprehensive framework for aspect-oriented programming in Microsoft .NET and is used in production by thousands of professional software developers every day.
With PostSharp, software developers can encapsulate implementation patterns into classes called aspects, and apply these aspects to their code using custom attributes.
PostSharp provides the following aspect primitives, from which to build your own:
For instance, this aspect writes a message before and after the method executions to which it is applied:
[Serializable] public class TraceAttribute : OnMethodBoundaryAspect { public override void OnEntry(MethodExecutionEventArgs args) { Trace.TraceInformation("Entering {0}.", args.Method); } public override void OnExit(MethodExecutionEventArgs args) { Trace.TraceInformation("Leaving {0}.", args.Method); } }
PostSharp offers several ways to add aspects to code:
By default, aspects are also custom attributes. With PostSharp, you can apply aspects directly to the code you want to enhance:
[Trace] public void CreateCustomer(int id, string name) { /* ... */ }
This feature enables you to add an aspect to a several targets with a single line of code:
[assembly: Trace( AttributeTargetTypes="MyApp.BusinessProcesses.*", AttributeTargetMemberAttributes = AttributeTargetElements.Public )]
When declarative options are not enough, write an IAspectProvider and
unleash the full power of System.Reflection and LINQ.
[MulticastAttributeUsage(MulticastTargets.Field | MulticastTargets.Property, TargetMemberAttributes = MulticastAttributes.Public | MulticastAttributes.Instance)] public sealed class AddXmlIgnoreAttribute : MethodLevelAspect, IAspectProvider { private static readonly CustomAttributeIntroductionAspect customAttributeIntroductionAspect = new CustomAttributeIntroductionAspect( new ObjectConstruction(typeof(XmlIgnoreAttribute).GetConstructor(Type.EmptyTypes))); public IEnumerable<AspectInstance> ProvideAspects(object targetElement) { MemberInfo memberInfo = (MemberInfo)targetElement; if (memberInfo.IsDefined(typeof(XmlElementAttribute), false) || memberInfo.IsDefined(typeof(XmlAttributeAttribute), false)) yield break; yield return new AspectInstance(targetElement, customAttributeIntroductionAspect); } }
Apply aspects automatically to all types or methods derived from the initial target of the aspect. This works with classes, interfaces, abstract methods, virtual methods, and interface methods.
[NotifyPropertyChanged(AttributeInheritance = MulticastInheritance.Strict)] public abstract class Entity { }
PostSharp instantiates and initializes aspects at build time, then serializes and stores them as a managed resource in the transformed assembly. Aspects are deserialized and executed at run time, leaving the expensive work until build time, which means applications start faster.
Sometimes patterns can't be described as a single primitive transformation. Composite aspects allow for the development of more complex patterns made of several transformations.
Composite aspects include the following features:
| Feature | Description |
|---|---|
| Advices | An advice is a method that adds a behavior to an existing element of code (see above, aspect primitives). |
| Pointcut | A pointcut is an expression (declarative or imperative) that returns the set of code elements to which an advice should be applied. |
| Member Introduction | Add methods, properties or events to the target class. |
| Interface Introduction | Make the target class introduce a new interface. |
| Member Import | Access non-public methods, properties or events from the aspect. |