Open sandboxFocusImprove this doc

LA0137: Dynamic Advice Bound to a Member Outside the Aspect

Severity Error
Reported by PostSharp
Message Error in dynamic advice <AdviceType> provided by the IAdviceProvider implementation of aspect "<Aspect>" applied to "<Target>": "<Member>" is not declared in the aspect type.

Cause

An aspect that implements IAdviceProvider returns advices from its ProvideAdvices(object) method. Some of these advices refer to a member of the aspect class: an ImportLocationAdviceInstance or an ImportMethodAdviceInstance stores the imported member in a field of the aspect, and an IntroduceMethodAdviceInstance copies a method of the aspect into the target class. PostSharp reports LA0137 when this member, <Member>, is not declared in the aspect class or in one of its base classes, for example when it is a field of the target class.

<AdviceType> is the class of the advice, and <Target> the declaration to which the aspect is applied. PostSharp reports the message on the aspect class, once for each faulty advice, and skips these advices.

In the following example, the [Describe] aspect passes the two arguments of the ImportLocationAdviceInstance constructor in the wrong order: the first one is a field of Customer instead of the Fields field of the aspect.

using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Reflection;
using PostSharp.Serialization;

namespace Errors.LA0137_Error;

// PostSharp reports the error on the aspect class: ProvideAdvices binds the advices to fields of the target class.
[PSerializable]
public class DescribeAttribute : InstanceLevelAspect, IAdviceProvider
{
    [PNonSerialized]
    public List<ILocationBinding>? Fields;

    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        Type targetType = (Type) targetElement;
        FieldInfo aspectField = typeof(DescribeAttribute).GetField( nameof(this.Fields) )!;

        foreach ( FieldInfo field in targetType.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly ) )
        {
            // The two arguments are swapped.
            yield return new ImportLocationAdviceInstance( field, new LocationInfo( aspectField ) );
        }
    }

    public override void RuntimeInitializeInstance()
    {
        foreach ( ILocationBinding binding in this.Fields! )
        {
            Console.WriteLine( $"{binding.LocationInfo.Name} = {binding.GetValue( this.Instance! )}" );
        }
    }
}

[Describe]
public class Customer
{
    private string name = "Alice";
    private int orderCount = 3;

    public override string ToString() => $"{this.name}, {this.orderCount} orders";
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine( new Customer() );
    }
}
error LA0137: LA0137_Error.cs(13,14): Error in dynamic advice ImportLocationAdviceInstance provided by the IAdviceProvider implementation of aspect "Errors.LA0137_Error.DescribeAttribute" applied to "Errors.LA0137_Error.Customer": "Errors.LA0137_Error.Customer.name" is not declared in the aspect type.
error LA0137: LA0137_Error.cs(13,14): Error in dynamic advice ImportLocationAdviceInstance provided by the IAdviceProvider implementation of aspect "Errors.LA0137_Error.DescribeAttribute" applied to "Errors.LA0137_Error.Customer": "Errors.LA0137_Error.Customer.orderCount" is not declared in the aspect type.

Resolution

Pass a member of the aspect class where the advice expects one: for an import advice, the field of the aspect that receives the imported member, which you get with typeof(MyAspect).GetField( ... ), and the member of the target class as the location or method to import. For an introduction, pass a public method of the aspect.

In the following example, the aspect field comes first, and the aspect receives the two fields of Customer.

using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Reflection;
using PostSharp.Serialization;

namespace Errors.LA0137_Fixed;

[PSerializable]
public class DescribeAttribute : InstanceLevelAspect, IAdviceProvider
{
    [PNonSerialized]
    public List<ILocationBinding>? Fields;

    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        Type targetType = (Type) targetElement;
        FieldInfo aspectField = typeof(DescribeAttribute).GetField( nameof(this.Fields) )!;

        foreach ( FieldInfo field in targetType.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly ) )
        {
            // The first argument is the field of the aspect, the second one the field of the target class.
            yield return new ImportLocationAdviceInstance( aspectField, new LocationInfo( field ) );
        }
    }

    public override void RuntimeInitializeInstance()
    {
        foreach ( ILocationBinding binding in this.Fields! )
        {
            Console.WriteLine( $"{binding.LocationInfo.Name} = {binding.GetValue( this.Instance! )}" );
        }
    }
}

[Describe]
public class Customer
{
    private string name = "Alice";
    private int orderCount = 3;

    public override string ToString() => $"{this.name}, {this.orderCount} orders";
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine( new Customer() );
    }
}
name = Alice
orderCount = 3
Alice, 3 orders

See Also

Reference

IAdviceProvider
ImportLocationAdviceInstance
ImportMethodAdviceInstance
IntroduceMethodAdviceInstance

Other Resources

Providing Advices Dynamically