Open sandboxFocusImprove this doc

Understanding Attribute Multicasting

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, and 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.

[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, nor to its constructors.

Tip

In addition 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

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. Only the attribute user can set the values of these properties.

As an aspect developer, do not set the values of these properties in the aspect construtor. Instead, use multicast filtering or programmatic validation of aspect usage described in the section Developer-Specified Filtering.

As an aspect user, it is important to understand that you can only apply aspects to elements of code 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:

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

Filtering Properties

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

T:PostSharp.Extensibility.MulticastAttribute Property (for ;aspect users) T:PostSharp.Extensibility.MulticastAttributeUsageAttribute Property (for aspect developers) 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

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: they can restrict the set of possible targets supported by the aspect, but cannot enlarge it.