| 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