Open sandboxFocusImprove this doc

LA0236: Binding Used Twice in an Advice

Severity Warning
Reported by PostSharp
Message The parameter "<Parameter>" of the advice "<Advice>" is bound by <Binding>, but the advice already has a parameter bound by <Binding>.

Cause

An advice can have at most one parameter annotated with FlowBehaviorAttribute, and at most one annotated with AwaiterAttribute. PostSharp reports LA0236 on each additional parameter, but still builds the advice:

  • With several [FlowBehavior] parameters, the woven code reads only the last one, and ignores the values set to the others.
  • Several [Awaiter] parameters share one awaiter variable.

The same mistake with ReturnValueAttribute or ExceptionAttribute causes the error LA0214 instead.

In the following example, the entry advice of the [RequiresReports] aspect sets the first [FlowBehavior] parameter to FlowBehavior.Return, but the woven code reads the second one, so Generate still runs.

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

namespace Errors.LA0236_Error;

public static class FeatureFlags
{
    public static bool ReportsEnabled => false;
}

[PSerializable]
public class RequiresReportsAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public static void OnEntry( [DeclarationName] string methodName,
                                [FlowBehavior] out FlowBehavior flowBehavior,
                                // A second [FlowBehavior] parameter: only this one is read.
                                [FlowBehavior] out FlowBehavior defaultBehavior )
    {
        defaultBehavior = FlowBehavior.Default;
        flowBehavior = FlowBehavior.Default;

        if ( !FeatureFlags.ReportsEnabled )
        {
            Console.WriteLine( $"Skipping {methodName} because reports are disabled." );
            flowBehavior = FlowBehavior.Return;
        }
    }
}

public class ReportService
{
    [RequiresReports]
    public void Generate()
    {
        Console.WriteLine( "Generating the report." );
    }
}

public static class Program
{
    public static void Main()
    {
        new ReportService().Generate();
    }
}
warning LA0236: LA0236_Error.cs(20,65): The parameter "defaultBehavior" of the advice "Errors.LA0236_Error.RequiresReportsAttribute.OnEntry(System.String, PostSharp.Aspects.FlowBehavior@, PostSharp.Aspects.FlowBehavior@)" is bound by [FlowBehavior], but the advice already has a parameter bound by [FlowBehavior].
Skipping Generate because reports are disabled.
Generating the report.

Resolution

Keep a single parameter of each binding in the advice, and set the value through it.

In the following example, the advice has one [FlowBehavior] parameter, and Generate is skipped.

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

namespace Errors.LA0236_Fixed;

public static class FeatureFlags
{
    public static bool ReportsEnabled => false;
}

[PSerializable]
public class RequiresReportsAttribute : MethodLevelAspect
{
    // The advice has a single [FlowBehavior] parameter.
    [OnMethodEntryAdvice]
    public static void OnEntry( [DeclarationName] string methodName,
                                [FlowBehavior] out FlowBehavior flowBehavior )
    {
        flowBehavior = FlowBehavior.Default;

        if ( !FeatureFlags.ReportsEnabled )
        {
            Console.WriteLine( $"Skipping {methodName} because reports are disabled." );
            flowBehavior = FlowBehavior.Return;
        }
    }
}

public class ReportService
{
    [RequiresReports]
    public void Generate()
    {
        Console.WriteLine( "Generating the report." );
    }
}

public static class Program
{
    public static void Main()
    {
        new ReportService().Generate();
    }
}
Skipping Generate because reports are disabled.

See Also

Reference

FlowBehaviorAttribute
AwaiterAttribute

Other Resources

Advice Parameters