Having multiple instances of the same custom attribute on the same target is sometimes a desired behavior. With multicasting attributes, it is easy to end up with that situation: many multicasting paths can lead to the same target.

However, most of the time, we would prefer a different behavior. We could define a method-level aspect on the type (this aspect would apply to all methods) and override the aspect on a specific method. What we require here is the possibility to replace an instance of a custom attribute by another. This scenario is fully supported by the multicasting framework.

The multicasting framework has both the ability to apply multiple custom attribute instances on the same target, and the ability to replace or override custom attributes. Note that we are here talking of custom attributes of the same type.

Applying multiple instances of the same custom attribute

The attribute developer can allow users to apply multiple instances of the same custom attribute by setting the AllowMultiple property of the MulticastAttributeUsageAttribute custom attribute to true:

[MulticastAttributeUsage( MulticastTargets.Class, AllowMultiple = true )]
public class MyAttribute : MulticastAttribute 
{ 
  public field string Tag; 
}

For instance, the following code results in three instance of the custom attribute:

[assembly: MyAttribute( AttributeTypes = "My*", Tag = "A" )]
[assembly: MyAttribute( AttributeTypeAttributes = MulticastAttributes.Public, Tag = "B" )]

[MyAttribute( Tag = "C" )]
public class MyClass {}

Deleting instances of a custom attribute

The AttributeExclude property of the MulticastAttribute class allows to remove any previous instance of the same custom attribute on a target.

This is useful, for instance, when you need to exclude a target from the matching set of a wildcard expression. For instance:

[assembly: Configurable( AttributeTypes = "BusinessLayer.*" )]

namespace BusinessLayer
{
  [Configurable( AttributeExclude = true )]
  public static class Helpers
  {

  }
}

Priority of custom attributes

Since the AttributeExclude custom attribute causes any previous custom attribute to be excluded, we need to precise the notion of precedence of custom attributes. Indeed, how can a custom attribute precede another one, when standard .NET attributes are unordered.

In order to disambiguate this issue, we have added a notion of priority to multicast custom attributes. The following rules apply:

Therefore, the following example is equivalent to the previous one:

[assembly: Configurable( AttributeTypes = "BusinessLayer.*", AttributePriority = 1 )]
[assembly: Configurable( AttributeTypes = "BusinessLayer.Helpers", 
   AttributeExclude = true, AttributePriority = 2 )]

namespace BusinessLayer
{
   class Helpers {}
}

Replacing instances of a custom attribute

Custom attribute replacement is enabled by the AttributeReplace property of the MulticastAttribute class. It is equivalent to a deletion followed by an insertion.

When it is not allowed to have multiple instances of the same custom attributes on a single target, the default behavior of multicast attributes is that the custom attribute with greater priority replaces the custom attribute of lower priority.

For instance, the following code applies a tag BusinessObject to all classes of the BusinessLayer namespace, expect to the class Helpers, to which the tag Helper is applied:

[assembly: Tag( "BusinessObject", 
                AttributeTypes = "BusinessLayer.*", 
                AttributePriority = 1 )]
[assembly: Tag( "Helper",
                AttributeTypes = "BusinessLayer.Helpers", 
                AttributePriority = 2 )]