| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot compose the type "<Type>" into the type "<TargetType>" because "<Type>" is not an interface. |
Cause
A CompositionAspect makes its target class implement interfaces, and delegates their members to an implementation object that its CreateImplementationObject method creates. The types that the aspect introduces are the ones that its GetPublicInterfaces method returns. A class can implement interfaces but cannot inherit from a second class, so each of these types must be an interface. PostSharp reports LA0037 for the first one that is not.
<Type> is the type returned by the aspect, and <TargetType> is the class to which the aspect is applied. The mistake usually comes from returning the class of the implementation object instead of the interface it implements.
In the following example, the [Auditable] aspect returns the AuditTrail class instead of the IAuditable interface.
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0037_Error;
public interface IAuditable
{
string Describe();
}
public class AuditTrail : IAuditable
{
private readonly object owner;
public AuditTrail( object owner )
{
this.owner = owner;
}
public string Describe() => $"Audit trail of {this.owner.GetType().Name}";
}
[PSerializable]
public class AuditableAttribute : CompositionAspect
{
// AuditTrail is a class, but a composition aspect can only introduce interfaces.
protected override Type[] GetPublicInterfaces( Type targetType ) => new[] { typeof(AuditTrail) };
public override object CreateImplementationObject( AdviceArgs args ) => new AuditTrail( args.Instance );
}
[Auditable]
public class Invoice
{
}
public static class Program
{
public static void Main()
{
var invoice = (IAuditable) (object) new Invoice();
Console.WriteLine( invoice.Describe() );
}
}
error LA0037: LA0037_Error.cs(34,14): Cannot compose the type "Errors.LA0037_Error.AuditTrail" into the type "Errors.LA0037_Error.Invoice" because "Errors.LA0037_Error.AuditTrail" is not an interface.
Resolution
Return interfaces only from GetPublicInterfaces. The implementation object can be of any class, as long as it implements these interfaces.
In the following example, the aspect introduces IAuditable, and an AuditTrail object implements it.
using System;
using PostSharp.Aspects;
using PostSharp.Serialization;
namespace Errors.LA0037_Fixed;
public interface IAuditable
{
string Describe();
}
public class AuditTrail : IAuditable
{
private readonly object owner;
public AuditTrail( object owner )
{
this.owner = owner;
}
public string Describe() => $"Audit trail of {this.owner.GetType().Name}";
}
[PSerializable]
public class AuditableAttribute : CompositionAspect
{
// The aspect introduces the interface, and the AuditTrail object implements it.
protected override Type[] GetPublicInterfaces( Type targetType ) => new[] { typeof(IAuditable) };
public override object CreateImplementationObject( AdviceArgs args ) => new AuditTrail( args.Instance );
}
[Auditable]
public class Invoice
{
}
public static class Program
{
public static void Main()
{
var invoice = (IAuditable) (object) new Invoice();
Console.WriteLine( invoice.Describe() );
}
}
Audit trail of Invoice
See Also
Reference
Other Resources