A type-level aspect applies to a type, and an assembly-level aspect applies to an assembly. One such aspect can transform several members of its target, introduce new members into the target type, and access the existing members of the target type. This kind of aspect implements design patterns that span a whole class, such as INotifyPropertyChanged or a threading model.
The aspect derives from one of the following classes:
| Base class | Target | Aspect instances |
|---|---|---|
| TypeLevelAspect | A class, a struct or an interface | One instance per target type. |
| InstanceLevelAspect | A class that is not static | One instance per instance of the target class, so the aspect can have a state for each object (see Understanding Aspect Lifetime and Scope). Introductions and imports of members require this base class. |
| AssemblyLevelAspect | An assembly | One instance per assembly. Its advices need a MethodPointcut, and it cannot introduce or import members. |
The aspect class contains:
- advice methods, which add behaviors to members of the target. They are written as in member-level aspects (see Advice Methods), and their parameters receive typed values of the target (see Advice Parameters).
- pointcuts, custom attributes on the advice methods that select the members to which each advice applies (see Selecting Members with Pointcuts).
- members that the aspect introduces into the target type, or that the aspect imports from it (see Introducing Interfaces, Methods, Properties and Events into Existing Classes and Accessing Members of the Target Class).
To add behaviors to a single method, field, property or event, a member-level aspect is simpler (see Developing Member-Level Aspects).
Example
The following aspect writes a line to the console whenever an instance property of the target class is set. The pointcut selects the properties, and the advice is generic, so the value is not boxed. Apply it to classes only: on a struct, the instance parameter receives a boxed copy, so the value would be stored in the copy.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Extensibility;
using PostSharp.Serialization;
[PSerializable]
public sealed class TracePropertiesAttribute : TypeLevelAspect
{
[OnLocationSetValueAdvice,
MulticastPointcut( Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Instance )]
public void OnPropertySet<T>( [This] object instance,
[DeclarationName( IncludeTypeName = true )] string propertyName,
[LocationValue] T value,
[Binding] ILocationBinding<T> binding )
{
Console.WriteLine( "{0} = {1}", propertyName, value );
binding.SetValue( instance, value );
}
}
In this chapter
| Section | Description |
|---|---|
| Selecting Members with Pointcuts | This article explains how pointcuts select the members to which advices apply, and how advices are grouped into one transformation. |
| Introducing Interfaces, Methods, Properties and Events into Existing Classes | This article shows how to introduce an interface, method, property or event into the target class. The new interface or member is implemented by the aspect itself. |
| Accessing Members of the Target Class | This article shows how to import a member of the target class so that the aspect can invoke it through a delegate. It also explains how member introductions and imports interact. |
| Adding Aspects Dynamically | This article shows how an aspect can add other aspects to declarations that it selects with code. |
| Providing Advices Dynamically | This article shows how an aspect can provide import and introduction advices for each target with code. |
See Also
Reference
TypeLevelAspect
InstanceLevelAspect
AssemblyLevelAspect
PostSharp.Aspects.Advices
Other Resources