Open sandboxFocusImprove this doc

LA0275: Invalid Dependency Type

Severity Error
Reported by PostSharp
Message The aspect "<Aspect>" applied to "<Target>" attempts to introduce a dependency of type "<DependencyType>" with ImportDependencyAdviceInstance, which is not a valid dependency type. A dependency must be a reference type that contains no generic parameters.

Cause

An ImportDependencyAdviceInstance adds a constructor parameter and a field of the type passed to its constructor, the DependencyType. When the constructor receives null, it gets the service from RunTimeServiceLocator. This requires a reference type that the target class can declare, so PostSharp reports LA0275 when <DependencyType> is:

  • a value type, such as a struct or an enum;
  • a pointer or by-reference type;
  • a type that contains generic parameters, such as the open generic type IAuditLog<>.

PostSharp reports the error on <Target>, the declaration to which the aspect is applied.

In the following example, the [Audited] aspect requests IAuditLog<>, intending each class to receive a log of its own type.

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

namespace Errors.LA0275_Error;

public interface IAuditLog
{
    void Write( string message );
}

// A log whose messages are prefixed with the name of the class that writes them.
public interface IAuditLog<T> : IAuditLog
{
}

public sealed class ConsoleAuditLog<T> : IAuditLog<T>
{
    public void Write( string message ) => Console.WriteLine( $"[{typeof(T).Name}] {message}" );
}

[PSerializable]
public sealed class AuditedAttribute : MethodLevelAspect, IAdviceProvider
{
    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        // An open generic type is not a valid dependency type.
        yield return new ImportDependencyAdviceInstance( typeof(IAuditLog<>) ) { Name = "AuditLog" };
    }

    [OnMethodEntryAdvice]
    public static void OnEntry( [Declaration] MethodBase method, [ImportMember( "AuditLog" )] IAuditLog auditLog )
    {
        auditLog.Write( $"Executing {method.Name}." );
    }
}

public class OrderService
{
    [Audited]
    public void PlaceOrder( int orderId ) => Console.WriteLine( $"Placing order {orderId}." );
}

public static class Program
{
    public static void Main()
    {
        RunTimeServiceLocator.RegisterService<IAuditLog<OrderService>>( () => new ConsoleAuditLog<OrderService>() );
        new OrderService().PlaceOrder( 1 );
    }
}
error LA0275: LA0275_Error.cs(45,17): The aspect "Errors.LA0275_Error.AuditedAttribute" applied to "Errors.LA0275_Error.OrderService.PlaceOrder(System.Int32)" attempts to introduce a dependency of type "Errors.LA0275_Error.IAuditLog`1<T>" with ImportDependencyAdviceInstance, which is not a valid dependency type. A dependency must be a reference type that contains no generic parameters.

Resolution

  • For a generic service, construct the type in ProvideAdvices(object), for instance with the class that declares the target, and import it with a base type or interface of it.
  • For a value, request a reference type that holds it, such as an interface or a class of options.

In the following example, the aspect requests IAuditLog<OrderService> for the methods of OrderService, and the advice imports it by its Name as an IAuditLog.

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

namespace Errors.LA0275_Fixed;

public interface IAuditLog
{
    void Write( string message );
}

// A log whose messages are prefixed with the name of the class that writes them.
public interface IAuditLog<T> : IAuditLog
{
}

public sealed class ConsoleAuditLog<T> : IAuditLog<T>
{
    public void Write( string message ) => Console.WriteLine( $"[{typeof(T).Name}] {message}" );
}

[PSerializable]
public sealed class AuditedAttribute : MethodLevelAspect, IAdviceProvider
{
    public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
    {
        // The generic type is constructed with the class that declares the target method.
        Type declaringType = ((MethodBase) targetElement).DeclaringType!;
        yield return new ImportDependencyAdviceInstance( typeof(IAuditLog<>).MakeGenericType( declaringType ) ) { Name = "AuditLog" };
    }

    [OnMethodEntryAdvice]
    public static void OnEntry( [Declaration] MethodBase method, [ImportMember( "AuditLog" )] IAuditLog auditLog )
    {
        auditLog.Write( $"Executing {method.Name}." );
    }
}

public class OrderService
{
    [Audited]
    public void PlaceOrder( int orderId ) => Console.WriteLine( $"Placing order {orderId}." );
}

public static class Program
{
    public static void Main()
    {
        RunTimeServiceLocator.RegisterService<IAuditLog<OrderService>>( () => new ConsoleAuditLog<OrderService>() );
        new OrderService().PlaceOrder( 1 );
    }
}
[OrderService] Executing PlaceOrder.
Placing order 1.

See Also

Reference

ImportDependencyAdviceInstance
ImportMemberAttribute

Other Resources

Receiving Dependencies from the Constructors of the Target Class