Open sandboxFocusImprove this doc

Migrating PostSharp attribute multicasting to Metalama

Multicasting in PostSharp is a feature of all aspects that enables targeting several declarations using a single custom attribute or XML element in the postsharp.config configuration file. It is exposed by MulticastAttribute, the ultimate base type of all aspect classes.

In Metalama, multicasting is not implemented as a core feature but as an extension. This decision was made because the goal of adding an aspect to multiple declarations is better achieved in Metalama using fabrics. Therefore, you might eventually decide not to use multicasting. For more details, see Adding many aspects simultaneously.

Multicasting in Metalama is provided for backward compatibility with PostSharp. The objective is not to require PostSharp users to change their business code when migrating to Metalama, but only their aspect code. Multicasting in Metalama is implemented by the Metalama.Extensions.Multicast namespace. The implementation of this namespace is open source.

Enabling multicasting for a simple aspect

If your aspect is based on OverrideMethodAspect or OverrideFieldOrPropertyAspect, you can enable multicasting by changing the base class to OverrideMethodMulticastAspect or OverrideFieldOrPropertyMulticastAspect respectively. No other changes should be required.

The process is slightly more complex if your aspect is derived from another base class.

Enabling multicasting for a blank aspect

Below are general instructions to add the multicasting feature to any aspect. You can verify these instructions by examining the source code of OverrideMethodMulticastAspect or OverrideFieldOrPropertyMulticastAspect.

Step 1. Derive your class from MulticastAspect and implement IAspect as appropriate

The simplest approach is for your aspect to derive from MulticastAspect instead of any other class.

The MulticastAspect class defines:

Your aspect must also implement the IAspect<T> interface for all relevant types of declarations:

  • on the final declarations where the aspect is actually applied (i.e., performs some actual work), and
  • on any intermediate declaration where the aspect does no work other than multicasting itself to select child declarations.

The MulticastAspect class already implements the IAspect<ICompilation> and IAspect<INamedType> interfaces and correctly implements the BuildAspect method. For the interfaces you implement yourself, you must implement BuildAspect.

Step 2. Implement the BuildAspect methods

Your implementation of the BuildAspect method should only call the this.Implementation.BuildAspect* method. The arguments you need to pass depend on the kind of declaration of the implemented IAspect<T> interface:

Example:

public void BuildAspect( IAspectBuilder<IMethod> builder )
{
    this.Implementation.BuildAspect(
        builder,
        b => b.Override( nameof(this.TheTemplate) ) );
}

Step 3. Implement eligibility

If your aspect has eligibility requirements on the type to which it is applied, override the BuildEligibility method.

Instead of repeating this eligibility condition in the BuildEligibility method for all final destinations of the aspect, you can call the BuildEligibility(INamedType) method as follows:

public override void BuildEligibility( IEligibilityBuilder<INamedType> builder )
{
    // Do not offer the aspect on static types.
    builder.MustNotBeStatic();
}

public void BuildEligibility( IEligibilityBuilder<IMethod> builder )
{
    // Include the conditions of the declaring type.
    this.BuildEligibility( builder.DeclaringType() );

    // Conditions that are specific to the method.
    builder.MustNotBeAbstract();
}