Open sandboxFocusImprove this doc

LA0249: Type Requested for Ahead-of-Time Compilation Cannot Be Instantiated

Severity Warning
Reported by PostSharp
Message The type "<Type>" that the aspect "<Aspect>" requests with InstantiateTypeAdviceInstance is not instantiated, because <Reason>. An application compiled ahead of time may have no native code for this type.

Cause

In an application compiled ahead of time, such as with NativeAOT, a generic type instance over a value type has native code only when the code of the application instantiates it. An aspect that creates such a type by reflection at run time returns an InstantiateTypeAdviceInstance from ProvideAdvices(object), and PostSharp adds an instantiation of the type to the woven assembly, in a method that is never called.

The advice has an effect only when the MSBuild property PostSharpAotCompatibleWeaving is true, which is its default when the project sets PublishAot, IsAotCompatible or EnableAotAnalyzer. PostSharp then reports LA0249 and skips the type when it cannot write the instantiation. <Reason> tells why:

  • The type is a generic type definition, contains generic parameters, or is an interface, an abstract class, an array, a pointer or a by-reference type.
  • The type cannot be resolved in the woven module.
  • The type is a class without a parameterless constructor.

PostSharp reports the warning on the aspect class, not on the code that returns the advice.

In the following example, the [LogArguments] aspect creates an ArgumentFormatter<T> for each parameter of the target method, but requests the generic type definition ArgumentFormatter<>. The @Property(AotCompatibleWeaving=True) directive sets the property as PostSharpAotCompatibleWeaving would.

// @Property(AotCompatibleWeaving=True)

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

namespace Errors.LA0249_Error;

public interface IArgumentFormatter
{
    string Format( object? value );
}

public sealed class ArgumentFormatter<T> : IArgumentFormatter
{
    public string Format( object? value ) => $"{typeof(T).Name} {value}";
}

[PSerializable]
public class LogArgumentsAttribute : OnMethodBoundaryAspect, IAdviceProvider
{
    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        foreach ( ParameterInfo parameter in ((MethodBase) targetElement).GetParameters() )
        {
            // The generic type definition cannot be instantiated: PostSharp reports the warning on the aspect class.
            yield return new InstantiateTypeAdviceInstance( typeof(ArgumentFormatter<>) );
        }
    }

    public override void OnEntry( MethodExecutionArgs args )
    {
        ParameterInfo[] parameters = args.Method.GetParameters();

        for ( int i = 0; i < parameters.Length; i++ )
        {
            Type formatterType = typeof(ArgumentFormatter<>).MakeGenericType( parameters[i].ParameterType );
            IArgumentFormatter formatter = (IArgumentFormatter) Activator.CreateInstance( formatterType )!;
            Console.WriteLine( $"{parameters[i].Name}: {formatter.Format( args.Arguments[i] )}" );
        }
    }
}

public class OrderService
{
    [LogArguments]
    public void PlaceOrder( int quantity ) => Console.WriteLine( $"Placing an order of {quantity} items." );
}

public static class Program
{
    public static void Main()
    {
        new OrderService().PlaceOrder( 3 );
    }
}
warning LA0249: LA0249_Error.cs(23,14): The type "Errors.LA0249_Error.ArgumentFormatter`1<T>" that the aspect "Errors.LA0249_Error.LogArgumentsAttribute" requests with InstantiateTypeAdviceInstance is not instantiated, because it must be a class or a structure without generic parameters. An application compiled ahead of time may have no native code for this type.

Resolution

Request the type that the aspect creates at run time:

  • For a generic type, close it with the type arguments that the aspect uses, with MakeGenericType, for instance with the type of a parameter of the target method.
  • Request a concrete class with a parameterless constructor, or a structure. The constructor can have any accessibility, because the woven code never calls it.

In the following example, the aspect requests ArgumentFormatter<int> for the quantity parameter. Under the just-in-time compiler, the program runs the same as without the advice.

// @Property(AotCompatibleWeaving=True)

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

namespace Errors.LA0249_Fixed;

public interface IArgumentFormatter
{
    string Format( object? value );
}

public sealed class ArgumentFormatter<T> : IArgumentFormatter
{
    public string Format( object? value ) => $"{typeof(T).Name} {value}";
}

[PSerializable]
public class LogArgumentsAttribute : OnMethodBoundaryAspect, IAdviceProvider
{
    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        foreach ( ParameterInfo parameter in ((MethodBase) targetElement).GetParameters() )
        {
            // The aspect requests the type that it creates at run time, with the type argument of the parameter.
            yield return new InstantiateTypeAdviceInstance( typeof(ArgumentFormatter<>).MakeGenericType( parameter.ParameterType ) );
        }
    }

    public override void OnEntry( MethodExecutionArgs args )
    {
        ParameterInfo[] parameters = args.Method.GetParameters();

        for ( int i = 0; i < parameters.Length; i++ )
        {
            Type formatterType = typeof(ArgumentFormatter<>).MakeGenericType( parameters[i].ParameterType );
            IArgumentFormatter formatter = (IArgumentFormatter) Activator.CreateInstance( formatterType )!;
            Console.WriteLine( $"{parameters[i].Name}: {formatter.Format( args.Arguments[i] )}" );
        }
    }
}

public class OrderService
{
    [LogArguments]
    public void PlaceOrder( int quantity ) => Console.WriteLine( $"Placing an order of {quantity} items." );
}

public static class Program
{
    public static void Main()
    {
        new OrderService().PlaceOrder( 3 );
    }
}
quantity: Int32 3
Placing an order of 3 items.

See Also

Reference

InstantiateTypeAdviceInstance
IAdviceProvider

Other Resources

Providing Advices Dynamically
Well-Known MSBuild Properties