Open sandboxFocusImprove this doc

LA0059: Two Advices of the Same Kind in One Group

Severity Error
Reported by PostSharp
Message Conflicting advices in aspect "<Aspect>": the methods "<FirstAdvice>" and "<SecondAdvice>" are advices of the same kind in the same group, but a group can have only one advice of each kind. Merge the two advices, or give one of them a group of its own, with another value of the Group property or with a pointcut and no Group property.

Cause

PostSharp weaves the advices of a group as one transformation: the method boundary advices of a group become one try / catch / finally construct, and the interception advices of a group one interception of the method, property or event. A group can therefore contain only one advice of each kind: one entry advice, one exit advice, one getter advice, and so on.

PostSharp reports LA0059 on the second advice of a kind that a group receives:

  • Most often, the Group property gives two advices of the same kind the same group name. The name is shared by all the classes of the aspect, so the two advices can also be declared in a base class and a derived class.
  • The obsolete Master property can do the same, when it names an advice whose group already has an advice of this kind.
  • An advice without pointcut and without Group joins the group of its class that has no advice of its kind yet. When two such advices of the same kind find the same group, for instance two exit advices and one entry advice, both join it.

In the following example, the LogEntry and CheckArguments methods of the [Log] aspect are both entry advices of the Logging group.

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

namespace Errors.LA0059_Error;

[PSerializable]
public class LogAttribute : TypeLevelAspect
{
    [OnMethodEntryAdvice( Group = "Logging" ), MulticastPointcut( MemberName = "*Order" )]
    public void LogEntry( MethodExecutionArgs args )
    {
        Console.WriteLine( $"Entering {args.Method.Name}" );
    }

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

    // A second entry advice in the Logging group, which already has one.
    [OnMethodEntryAdvice( Group = "Logging" )]
    [AdviceDependency( AspectDependencyAction.Order, AspectDependencyPosition.After, nameof(LogEntry) )]
    public void CheckArguments( MethodExecutionArgs args )
    {
        Console.WriteLine( $"Checking {args.Arguments.Count} argument(s)" );
    }
}

[Log]
public class OrderService
{
    public void PlaceOrder( string product )
    {
        Console.WriteLine( $"Order placed for {product}" );
    }
}

public static class Program
{
    public static void Main()
    {
        new OrderService().PlaceOrder( "Coffee" );
    }
}
error LA0059: LA0059_Error.cs(27,17): Conflicting advices in aspect "Errors.LA0059_Error.LogAttribute": the methods "LogEntry" and "CheckArguments" are advices of the same kind in the same group, but a group can have only one advice of each kind. Merge the two advices, or give one of them a group of its own, with another value of the Group property or with a pointcut and no Group property.

Resolution

  • Merge the two advices into one method, when they always apply to the same declarations.
  • Or give one of them a group of its own: remove its Group property and give it a pointcut, or give it another Group value. A group without pointcut applies to the target of the aspect, which must then be a declaration that the advice accepts; otherwise, PostSharp reports LA0049. Two groups that both apply to the target of the aspect are reported as LA0257.

Two groups on the same declaration are two transformations, so order them with an AdviceDependencyAttribute, which can name any advice of a group.

In the following example, CheckArguments has no Group property any more: its pointcut starts a group of its own, which runs after the Logging group. The class then has two groups without exit advice, so LogExit selects the Logging group with the Group property.

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

namespace Errors.LA0059_Fixed;

[PSerializable]
public class LogAttribute : TypeLevelAspect
{
    [OnMethodEntryAdvice( Group = "Logging" ), MulticastPointcut( MemberName = "*Order" )]
    public void LogEntry( MethodExecutionArgs args )
    {
        Console.WriteLine( $"Entering {args.Method.Name}" );
    }

    // The class has two groups without exit advice, so the Group property selects the Logging group.
    [OnMethodExitAdvice( Group = "Logging" )]
    public void LogExit( MethodExecutionArgs args )
    {
        Console.WriteLine( $"Leaving {args.Method.Name}" );
    }

    // Without Group, the pointcut starts a group of its own, which runs after the Logging group.
    [OnMethodEntryAdvice, MulticastPointcut( MemberName = "*Order" )]
    [AdviceDependency( AspectDependencyAction.Order, AspectDependencyPosition.After, nameof(LogEntry) )]
    public void CheckArguments( MethodExecutionArgs args )
    {
        Console.WriteLine( $"Checking {args.Arguments.Count} argument(s)" );
    }
}

[Log]
public class OrderService
{
    public void PlaceOrder( string product )
    {
        Console.WriteLine( $"Order placed for {product}" );
    }
}

public static class Program
{
    public static void Main()
    {
        new OrderService().PlaceOrder( "Coffee" );
    }
}
Entering PlaceOrder
Checking 1 argument(s)
Order placed for Coffee
Leaving PlaceOrder

See Also

Reference

Group
MulticastPointcut
AdviceDependencyAttribute

Other Resources

Selecting Members with Pointcuts
Ordering Advices