Post­Sharp Documentation / Adding Aspects to Code / Adding Aspects Declaratively Using Attributes / Adding Aspects to Multiple Declarations Using Attributes / Understanding Attribute Multicasting

Understanding Attribute Multicasting

This topic contains the following sections:

  • Overview of the Multicasting Algorithm
  • Filtering Target Elements of Code
  • Filtering Properties
  • Overriding Filtering Attributes
Overview of the Multicasting Algorithm

Every multicast attribute class must be assigned a set of legitimate targets using the MulticastAttributeUsageAttribute custom attribute, which is the equivalent and complement of AttributeUsageAttribute for multicast attributes. Multicast attributes can be applied to types, methods, fields, properties, events, or/or parameters. For instance, a caching aspect targets methods. A field validation aspect targets fields.

When a field-level multicast attribute is applied to a type, the attribute is implicitly applied to all fields of that type. When it is applied to an assembly, it is implicitly applied to all fields of that assembly.

The general rule is: when a multicast attribute is applied to a container, it is implicitly (and recursively) applied to all elements of that container.

The next table illustrates how this rule translates for different kinds of targets.

Directly applied to

Implicitly applied to

Assembly or Module

Types, methods, fields, properties, parameters, and events contained in this assembly or module.

Type

Methods, fields, properties, parameters, and events contained in this type.

Property or Event

Accessors of this property or event.

Method

This method and the parameters of this method.

Field

This field.

Parameter

This parameter.

Filtering Target Elements of Code

Note that the default behavior is maximalist: we apply the attribute to all contained elements. However, PostSharp provides a way to restrict the set of elements to which the attribute is multicast: filtering.

Both the attribute developer and the user of the aspect can specify filters.

Developer-Specified Filtering

Just like normal custom attributes should be decorated with the [AttributeUsage] custom attribute, multicast custom attributes must be decorated by the [MulticastAttributeUsage] attribute (see MulticastAttributeUsageAttribute). It specifies which are the valid targets of the multicast attributes.

For instance, the following piece of code specifies that the attribute GuiThreadAttribute can be applied to instance methods. Aspect users experience a build-time error when trying to use this aspect on a constructor or static method.

C#
[MulticastAttributeUsage(MulticastTargets.Method, TargetMemberAttributes = MulticastAttributes.Instance)]
[AttributeUsage(AttributeTargets.Assembly|AttributeTargets.Class|AttributeTargets.Method, AllowMultiple = true)]
[PSerializable]
public class GuiThreadAttribute : MethodInterceptionAspect
{
// Details skipped.
}

Note the presence of the AttributeUsageAttribute attribute in the sample above. It tells the C# or VB compiler that the attribute can be directly applied to assemblies, classes, constructors, or methods. But this aspect will never be eventually applied to an assembly or a class. Indeed, the MulticastAttributeUsageAttribute attribute specifies that the sole valid targets are methods. Furthermore, the TargetMemberAttributes property establishes a filter that includes only instance methods.

Therefore, if the aspect is applied to a type containing an abstract method, the aspect will not be multicast to this method, neither to its constructors.

Tip Tip

Additionally to multicast filtering, consider using programmatic validation of aspect usage. Any custom attribute can implement IValidableAnnotation to implement build-time validation of targets. Aspects that derive from Aspect already implement these interfaces: your aspect can override the method CompileTimeValidate(Object).

Tip Tip

As an aspect developer, you should enforce as many restrictions as necessary to ensure that your aspect is only used in the way you intended, and raise errors in other cases. Using an aspect in an unexpected way may result in runtime errors that are difficult to debug.

User-Specified Filtering

The attribute user can specify multicasting filters using specific properties of the MulticastAttribute class. To make it clear that these properties only impact the multicasting process, they have the prefix Attribute.

As an aspect user, it is important to understand that you can only apply aspects to elements of codes that have been allowed by the developer of the aspect.

For instance, the following element of code adds a tracing aspect to all public methods of a namespace:

C#
[assembly: Trace( AttributeTargetTypes="AdventureWorks.BusinessLayer.*", AttributeTargetMemberAttributes = MulticastAttributes.Public )]
Filtering Properties

The following table lists the filters available to users and developers of aspects:

MulticastAttribute Property

MulticastAttributeUsageAttribute Property

Description

AttributeTargetElements

ValidOn

Restricts the kinds of targets (assemblies, classes, value types, delegates, interfaces, properties, events, properties, methods, constructors, parameters) to which the attribute can be indirectly applied.

AttributeTargetAssemblies

Wildcard expression or regular expression specifying to which assemblies the attribute is multicast.

AllowExternalAssemblies

Determines whether the aspect can be applied to elements defined in a different assembly than the current one.

AttributeTargetTypes

Wildcard expression or regular expression filtering by name the type to which the attribute is applied, or the declaring type of the member to which the attribute is applied.

AttributeTargetTypeAttributes

TargetTypeAttributes

Restricts the visibility of the type to which the aspect is applied, or of the type declaring the member to which the aspect is applied.

AttributeTargetMembers

Wildcard expression or regular expression filtering by name the member to which the attribute is applied.

AttributeTargetMemberAttributes

TargetMemberAttributes

Restricts the attributes (visibility, virtuality, abstraction, literality, ...) of the member to which the aspect is applied.

AttributeTargetParameters

Wildcard expression or regular expression specifying to which parameter the attribute is multicast.

AttributeTargetParameterAttributes

TargetParameterAttributes

Restricts the attributes (in/out/ref) of the parameter to which the aspect is applied.

AttributeInheritance

Inheritance

Specifies whether the aspect is propagated along the lines of inheritance of the target interface, class, method, or parameter (see Understanding Aspect Inheritance).

Caution note Caution

Whenever possible, do not rely on naming conventions to apply aspects (properties AttributeTargetTypes, AttributeTargetMembers and AttributeTargetParameters). This may work perfectly today, and break tomorrow if someone renames an element of code without being aware of the aspect.

Overriding Filtering Attributes

Suppose we have two classes A and B, B being derived from A. Both A and B can be decorated with MulticastAttributeUsageAttribute. However, since B is derived from A, filters on B cannot be more permissive than filters on A.

In other words, the MulticastAttributeUsageAttribute custom attribute is inherited. It can be overwritten in derived classes, but derived class cannot enlarge the set of possible targets. They can only restrict it.

Similarly (and hopefully predictably), the aspect user is subject to the same rule: she can restrict the set of possible targets supported by the aspect, but cannot enlarge it.