Open sandboxFocusImprove this doc

LA0269: Invalid Type of a Requested Field

Severity Error
Reported by PostSharp
Message The aspect "<Aspect>" applied to "<Target>" attempts to introduce a field of type "<FieldType>" with IntroduceFieldAdviceInstance, which is not a valid field type. By-reference types, pointers, void and types that contain generic parameters are not supported, and a byref-like type, such as Span<T>, is supported only as an instance field of a ref struct.

Cause

An aspect attempts to introduce a field by returning an IntroduceFieldAdviceInstance from ProvideAdvices. PostSharp reports LA0269 when the FieldType of the request is one of the following:

  • A by-reference type, such as the type of a ref parameter.
  • A pointer type, such as byte*.
  • void.
  • A type that contains generic parameters, such as the return type T of a generic method, or an open generic type.
  • A byref-like type, such as Span<T>, when the request is for a static field (IsStatic is true) or when the target type is not a ref struct.

<Target> is the declaration to which the aspect is applied, where the error is located.

In the following example, the [NativeBuffer] aspect attempts to introduce a field of type byte* to store the address of a native buffer.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0269_Error;

// Gives each object a native buffer, allocated on the first call of the target method.
[PSerializable]
public sealed unsafe class NativeBufferAttribute : MethodLevelAspect, IAdviceProvider
{
    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        // A pointer is not a valid type for a requested field.
        yield return new IntroduceFieldAdviceInstance( typeof(byte*) ) { Name = "buffer" };
    }

    [OnMethodEntryAdvice]
    public static void OnEntry( [ImportMember( "buffer" )] ref byte* buffer )
    {
        if ( buffer == null )
        {
            buffer = (byte*) Marshal.AllocHGlobal( 256 );
            Console.WriteLine( "Allocated a native buffer." );
        }
    }
}

public class Encoder
{
    [NativeBuffer]
    public void Encode( string text ) => Console.WriteLine( $"Encoding \"{text}\"." );
}

public static class Program
{
    public static void Main()
    {
        Encoder encoder = new Encoder();
        encoder.Encode( "first" );
        encoder.Encode( "second" );
    }
}
error LA0269: LA0269_Error.cs(34,17): The aspect "Errors.LA0269_Error.NativeBufferAttribute" applied to "Errors.LA0269_Error.Encoder.Encode(System.String)" attempts to introduce a field of type "System.Byte*" with IntroduceFieldAdviceInstance, which is not a valid field type. By-reference types, pointers, void and types that contain generic parameters are not supported, and a byref-like type, such as Span<T>, is supported only as an instance field of a ref struct.

Resolution

Request a field of a type that a field can have:

  • For a pointer, request a nint (nint) field, and convert it to a pointer in the advice.
  • For a by-reference type, request a field of the element type, which GetElementType returns.
  • For a type that depends on a generic parameter of a method, request a field of a closed type, such as object.
  • For a byref-like type, request an instance field in a ref struct, or store the data in a type that is not byref-like, such as an array or Memory<T>.

In the following example, the aspect stores the address of the buffer in an nint field, and allocates the buffer once for each object.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0269_Fixed;

// Gives each object a native buffer, allocated on the first call of the target method.
[PSerializable]
public sealed class NativeBufferAttribute : MethodLevelAspect, IAdviceProvider
{
    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        // The address of the buffer is stored in a native-sized integer.
        yield return new IntroduceFieldAdviceInstance( typeof(nint) ) { Name = "buffer" };
    }

    [OnMethodEntryAdvice]
    public static void OnEntry( [ImportMember( "buffer" )] ref nint buffer )
    {
        if ( buffer == 0 )
        {
            buffer = Marshal.AllocHGlobal( 256 );
            Console.WriteLine( "Allocated a native buffer." );
        }
    }
}

public class Encoder
{
    [NativeBuffer]
    public void Encode( string text ) => Console.WriteLine( $"Encoding \"{text}\"." );
}

public static class Program
{
    public static void Main()
    {
        Encoder encoder = new Encoder();
        encoder.Encode( "first" );
        encoder.Encode( "second" );
    }
}
Allocated a native buffer.
Encoding "first".
Encoding "second".

See Also

Reference

IntroduceFieldAdviceInstance
ImportMemberAttribute

Other Resources

Providing Advices Dynamically