Open sandboxFocusImprove this doc

LA0257: Several Groups of Advices Apply to the Target of the Aspect

Severity Warning
Reported by PostSharp
Message The aspect "<Aspect>" has several groups of advices of one family that apply to the target of the aspect: the groups of <Advices>. They are woven as separate transformations of the same declaration. Put the advices in one group with the Group property, which accepts one advice of each kind, or give the groups pointcuts.

Cause

Advices of the same family, such as the method boundary advices, are woven in groups, and each group is one transformation: the method boundary advices of a group share one try / catch / finally construct and one MethodExecutionArgs. A group without pointcut applies to the target of the aspect.

PostSharp reports LA0257 when the aspect type has several such groups of one family. They are two transformations of the same declaration, nested one in the other, which is rarely what you want. <Advices> lists the first advice of each group. The warning is reported even when one of the groups is selected with the Group property.

The groups usually come from one of these cases:

  • The aspect type and one of its base classes both declare advices of the family without pointcut. PostSharp infers the groups of each class separately and never looks at another class, so an advice of the derived class does not join a group of the base class, even when that group has no advice of its kind. The two classes then have one group each.
  • One class declares two advices of the same kind without pointcut. A group has one advice of each kind, so the second advice starts a group of its own.

In the following example, AuditedTraceAttribute adds a success advice to the entry and exit advices of its base class. The success advice starts a second group, which an advice dependency orders after the group of the base class; without it, PostSharp would also report the warning PS0114, because the order of the two groups would be nondeterministic.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Aspects.Dependencies;
using PostSharp.Serialization;

namespace Errors.LA0257_Error;

[PSerializable]
public class TraceAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"Entering {args.Method.Name}" );

    [OnMethodExitAdvice]
    public void OnExit( MethodExecutionArgs args ) => Console.WriteLine( $"Leaving {args.Method.Name}" );
}

[PSerializable]
public class AuditedTraceAttribute : TraceAttribute
{
    // The inference does not look at the base class, so this advice starts a second group that applies to the target method.
    [OnMethodSuccessAdvice]
    [AdviceDependency( AspectDependencyAction.Order, AspectDependencyPosition.After, nameof( OnEntry ) )]
    public void OnSuccess( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} succeeded" );
}

public class OrderService
{
    [AuditedTrace]
    public void PlaceOrder() => Console.WriteLine( "Placing the order" );
}

public static class Program
{
    public static void Main()
    {
        new OrderService().PlaceOrder();
    }
}
warning LA0257: LA0257_Error.cs(25,17): The aspect "Errors.LA0257_Error.AuditedTraceAttribute" has several groups of advices of one family that apply to the target of the aspect: the groups of "Errors.LA0257_Error.AuditedTraceAttribute.OnSuccess(PostSharp.Aspects.MethodExecutionArgs)", "Errors.LA0257_Error.TraceAttribute.OnEntry(PostSharp.Aspects.MethodExecutionArgs)". They are woven as separate transformations of the same declaration. Put the advices in one group with the Group property, which accepts one advice of each kind, or give the groups pointcuts.

Resolution

  • Put the advices in one group: set the Group property of all of them to the same name. The name is shared by the classes of the aspect, so an advice of a derived class can join a group of its base class. A group accepts one advice of each kind: merge two advices of the same kind into one method.
  • When the advices must apply to different declarations, give the groups pointcuts, such as MulticastPointcut or MethodPointcut.

In the following example, the three advices are in the Trace group, so the advice dependency is no longer needed.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0257_Fixed;

[PSerializable]
public class TraceAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice( Group = "Trace" )]
    public void OnEntry( MethodExecutionArgs args ) => Console.WriteLine( $"Entering {args.Method.Name}" );

    [OnMethodExitAdvice( Group = "Trace" )]
    public void OnExit( MethodExecutionArgs args ) => Console.WriteLine( $"Leaving {args.Method.Name}" );
}

[PSerializable]
public class AuditedTraceAttribute : TraceAttribute
{
    // The Group property puts this advice in the group of the base class.
    [OnMethodSuccessAdvice( Group = "Trace" )]
    public void OnSuccess( MethodExecutionArgs args ) => Console.WriteLine( $"{args.Method.Name} succeeded" );
}

public class OrderService
{
    [AuditedTrace]
    public void PlaceOrder() => Console.WriteLine( "Placing the order" );
}

public static class Program
{
    public static void Main()
    {
        new OrderService().PlaceOrder();
    }
}
Entering PlaceOrder
Placing the order
PlaceOrder succeeded
Leaving PlaceOrder

See Also

Reference

Group
AdviceDependencyAttribute
MulticastPointcut

Other Resources

Selecting Members with Pointcuts
Advice Methods