Open sandboxFocusImprove this doc

LA0223: Instance Passed by Reference to an Advice on a Class

Severity Error
Reported by PostSharp
Message The parameter "<Parameter>" of the advice "<Advice>" is bound by [This] and passed by reference, which is supported only when the type "<InstanceType>" is a struct.

Cause

A parameter annotated with ThisAttribute receives the instance of the target. When the parameter is passed by reference, with in or ref, it receives the address of the instance, so that the advice reads a struct without copying it, or changes it. Only a struct has such an address: the instance of a class is a reference already. When the advice applies to an instance member of a type that is not a struct, PostSharp reports LA0223 on the target member.

<InstanceType> is the type that declares the target member. On a static target, the parameter receives no instance, and this check does not apply.

When the advice uses a pointcut that skips the targets whose signature does not match, such as MatchPointcut, PostSharp skips the target instead of reporting the error.

In the following example, the entry advice of the [TraceState] aspect receives the instance with an in parameter, and the aspect is applied to a method of the Customer class.

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

namespace Errors.LA0223_Error;

[PSerializable]
public sealed class TraceStateAttribute : MethodLevelAspect
{
    [OnMethodEntryAdvice]
    public void OnEntry<T>( [DeclarationName] string methodName, [This] in T instance )
    {
        Console.WriteLine( $"{methodName}: {instance}" );
    }
}

public class Customer
{
    public string Name { get; set; } = "Alice";

    // The aspect receives the instance by reference, but Customer is a class.
    [TraceState]
    public void Rename( string name )
    {
        this.Name = name;
    }

    public override string ToString() => $"Customer {this.Name}";
}

public static class Program
{
    public static void Main()
    {
        new Customer().Rename( "Bob" );
    }
}
error LA0223: LA0223_Error.cs(24,17): The parameter "instance" of the advice "Errors.LA0223_Error.TraceStateAttribute.OnEntry``1(System.String, ``0@)" is bound by [This] and passed by reference, which is supported only when the type "Errors.LA0223_Error.Customer" is a struct.

Resolution

  • Pass the parameter by value. Its type can be object, the type of the instance, or a type parameter of the advice, which PostSharp infers from the target. The parameter then receives the reference to an object, or a copy of a struct.
  • Otherwise, apply the aspect only to members of structs.

In the following example, the [TraceState] aspect receives the instance by value.

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

namespace Errors.LA0223_Fixed;

[PSerializable]
public sealed class TraceStateAttribute : MethodLevelAspect
{
    // The instance is passed by value, which works for classes and structs.
    [OnMethodEntryAdvice]
    public void OnEntry<T>( [DeclarationName] string methodName, [This] T instance )
    {
        Console.WriteLine( $"{methodName}: {instance}" );
    }
}

public class Customer
{
    public string Name { get; set; } = "Alice";

    [TraceState]
    public void Rename( string name )
    {
        this.Name = name;
    }

    public override string ToString() => $"Customer {this.Name}";
}

public static class Program
{
    public static void Main()
    {
        new Customer().Rename( "Bob" );
    }
}
Rename: Customer Alice

See Also

Reference

ThisAttribute
AdviceParameterAttribute

Other Resources

Advice Parameters