| Severity | Error |
| Reported by | PostSharp |
| Message | The constructor "<Constructor>" of "<Type>" cannot receive the dependencies <Dependencies>: the constructor with the added parameters would have the signature of the constructor "<OtherConstructor>". Remove one of the two constructors. |
Cause
When an aspect attempts to introduce a dependency with ImportDependencyAdviceInstance, and the class has no field or readable instance property of the service type, PostSharp transforms each instance constructor of the class and of its derived classes. A constructor that has no parameter of exactly the service type gets an enhanced constructor: its own parameters followed by one parameter for each missing dependency. The original constructor becomes a forwarder that calls it.
PostSharp reports LA0278 on <Constructor> when its enhanced constructor would have the parameter types of <OtherConstructor>, which the class already declares. <Dependencies> lists the types of the parameters that PostSharp would add. A typical case is a parameterless constructor next to a constructor that receives the service.
In the following example, the parameterless constructor of OrderService would become OrderService( IAuditLog ).
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0278_Error;
public interface IAuditLog
{
void Write( string message );
}
public sealed class ConsoleAuditLog : IAuditLog
{
public void Write( string message ) => Console.WriteLine( message );
}
[PSerializable]
public sealed class AuditedAttribute : MethodLevelAspect, IAdviceProvider
{
public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
{
yield return new ImportDependencyAdviceInstance( typeof(IAuditLog) );
}
[OnMethodEntryAdvice]
public static void OnEntry( [Declaration] MethodBase method, [ImportMember] IAuditLog auditLog )
{
auditLog.Write( $"Executing {method.Name}." );
}
}
public class OrderService
{
// With the IAuditLog parameter added, this constructor would be OrderService( IAuditLog ).
public OrderService() : this( new ConsoleAuditLog() )
{
}
public OrderService( IAuditLog auditLog )
{
auditLog.Write( "Creating the order service." );
}
[Audited]
public void PlaceOrder( int orderId ) => Console.WriteLine( $"Placing order {orderId}." );
}
public static class Program
{
public static void Main()
{
new OrderService().PlaceOrder( 1 );
}
}
error LA0278: LA0278_Error.cs(38,12): The constructor "Errors.LA0278_Error.OrderService.#ctor" of "Errors.LA0278_Error.OrderService" cannot receive the dependencies Errors.LA0278_Error.IAuditLog: the constructor with the added parameters would have the signature of the constructor "Errors.LA0278_Error.OrderService.#ctor(Errors.LA0278_Error.IAuditLog)". Remove one of the two constructors.
Resolution
Remove one of the two constructors. Usually, remove the constructor that does not receive the service: the constructor that does receives the dependency of the aspect from its own parameter, and PostSharp does not change it. A container passes the service, and code that uses new passes it explicitly.
Declaring the missing parameters in <Constructor> does not help, because the constructor then has the parameter types of <OtherConstructor>, which C# rejects.
In the following example, only the constructor that receives the IAuditLog remains, and both the class and the aspect use the log that it receives.
using System;
using System.Collections.Generic;
using System.Reflection;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0278_Fixed;
public interface IAuditLog
{
void Write( string message );
}
public sealed class ConsoleAuditLog : IAuditLog
{
public void Write( string message ) => Console.WriteLine( message );
}
[PSerializable]
public sealed class AuditedAttribute : MethodLevelAspect, IAdviceProvider
{
public IEnumerable<AdviceInstance> ProvideAdvices( object targetElement )
{
yield return new ImportDependencyAdviceInstance( typeof(IAuditLog) );
}
[OnMethodEntryAdvice]
public static void OnEntry( [Declaration] MethodBase method, [ImportMember] IAuditLog auditLog )
{
auditLog.Write( $"Executing {method.Name}." );
}
}
public class OrderService
{
// The parameterless constructor is removed: this constructor already receives the IAuditLog.
public OrderService( IAuditLog auditLog )
{
auditLog.Write( "Creating the order service." );
}
[Audited]
public void PlaceOrder( int orderId ) => Console.WriteLine( $"Placing order {orderId}." );
}
public static class Program
{
public static void Main()
{
new OrderService( new ConsoleAuditLog() ).PlaceOrder( 1 );
}
}
Creating the order service.
Executing PlaceOrder.
Placing order 1.
See Also
Reference
ImportDependencyAdviceInstance
Other Resources
Receiving Dependencies from the Constructors of the Target Class