Overview
In .NET, you normally need to write one line of code for any application of a target attributes. If a custom attribute applies to all types of a namespace, you have to manually add the custom attribute to every single type.
By contrast, multicast custom attributes allow you to apply a custom attributes on multiple declarations by using wildcard or regular expressions, or by filtering on some attributes. It makes it easy to apply an aspect to, say, all public static methods of a namespace, with a single line of code.
Custom attributes supporting multicasting needs to be derived from MulticastAttribute. All PostSharp Laos aspects are derived from this class.
Note. Custom attribute multicasting is a feature of PostSharp. If you do not transform your assembly using PostSharp, multicast attributes will behave as plain old custom attributes.
Behavior of a multicast attribute
Multicast custom attributes have a set of valid targets: types, methods, fields, properties, or events. 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 on an assembly, it is implicitly applied to all fields of that assembly.
The general rule is: when a multicast attribute is applied on 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, and events contained in this assembly or module. |
| Type | Methods, fields, properties, and events contained in this type. |
| Property or Event | Accessors of this property or event. |
| Method | This method. |
| Field | This field. |
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 attribute user can specify filters.
Multicasting filters specified by the attribute developer
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 OnMethodBoundaryAspect, and all attributes
derived from it, apply on methods or constructors that are not
abstract and are implemented in managed code:
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class |
AttributeTargets.Constructor | AttributeTargets.Event |
AttributeTargets.Method | AttributeTargets.Property |
AttributeTargets.Struct,
AllowMultiple = true, Inherited = false)]
[MulticastAttributeUsage( MulticastTargets.Method | MulticastTargets.Constructor,
AllowMultiple=true,
TargetMemberAttributes =
MulticastAttributes.NonAbstract |
MulticastAttributes.Managed)]
public abstract class OnMethodBoundaryAspect ...
Note, in the sample above, the presence of the
AttributeUsage attribute. It tells the C# or Visual
Basic compiler that the attribute can be directly applied to
assemblies, classes, constructors, methods, and so on. But this
aspect will never be finally applied to an assembly or a class.
Indeed, the MulticastAttributeUsageAttribute
attribute specifies that the sole valid targets are methods and
constructors. Furthermore, the TargetMemberAttributes
property establishes a filter that includes only non abstract
methods written in managed code.
Therefore, if the aspect is applied on a type containing an abstract method, the aspect will not be multicast to this method.
The following table lists the filters available to the attribute developers:
| Filtering Property | Description |
|---|---|
ValidOn
|
Restricts the kinds of targets (assemblies, classes, value types, delegates, interfaces, properties, events, properties, methods, constructors) to which the attribute can be indirectly applied. |
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. |
TargetMemberAttributes
|
Restricts the attributes (visibility, virtuality, abstraction, literality, ...) of the member to which the aspect is applied. |
AllowExternalAssemblies
|
Determines whether the attribute can be applied to elements defined in a different assembly than the current one. |
Multicasting filters specified by the attribute user
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.
The following table lists the filters available to the attribute developers:
| Filtering Property | Description |
|---|---|
AttributeTargetElements
|
Restricts the kinds of targets (assemblies, classes, value types, delegates, interfaces, properties, events, properties, methods, constructors) to which the attribute can be indirectly applied. |
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
|
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
|
Restricts the attributes (visibility, virtuality, abstraction, literality, ...) of the member to which the aspect is applied. |
AttributeTargetAssemblies
|
Wildcard expression or regular expression specifying to which assemblies the attribute is multicast. |
Inheritance of filtering attributes
Suppose we have two classes A and B,
B being derived from A. Both
A and B can be decorated with the
[MulticastAttributeUsage]. However, since
B is derived from A, filters on
B cannot be more permissive than filters on
A.
In other words, the [MulticastAttributeUsage]
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 attribute user is subject to the same rule: she can restrict the set of possible targets supported by the aspect, but cannot enlarge it.
See also
Multiple Instances on the Same
Target
Persisting Custom Attributes
Metadata