| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot copy the internal attribute "<AttributeType>" to "<Target>", which is in another assembly. Make the attribute public, or remove it from the member of the aspect. |
Cause
When an aspect introduces a member with IntroduceMemberAttribute, PostSharp copies some custom attributes of the member of the aspect onto the introduced member:
- the attributes of the member itself that CopyCustomAttributesAttribute selects;
- all the attributes of the parameters, of the return value and of the generic parameters of an introduced method.
The introduced member belongs to the target type. When the target type is in another assembly than the aspect, and the type of a copied attribute is not visible from there, for example because it is internal, the target assembly would reference a type that it cannot access. PostSharp reports LA0201 instead.
<AttributeType> is the attribute type. <Target> is the introduced member for the attributes selected by CopyCustomAttributesAttribute, and the target type for the attributes of parameters, return values and generic parameters. When <Target> is an introduced member, the message has no file and line, because the member has no source code: look for the aspect that introduces it.
In the following example, the [Auditable] aspect of a library introduces a GetAuditTrail method and copies its internal [Audited] attribute.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0201_Error.Auditing;
// The attribute is internal to this library.
[AttributeUsage( AttributeTargets.Method )]
internal sealed class AuditedAttribute : Attribute
{
}
[PSerializable]
public class AuditableAttribute : InstanceLevelAspect
{
[IntroduceMember]
[CopyCustomAttributes( typeof(AuditedAttribute) )]
[Audited]
public string GetAuditTrail() => $"Audit trail of {this.Instance!.GetType().Name}";
}
The aspect is applied to a class of the application, in another assembly.
using System;
using Errors.LA0201_Error.Auditing;
namespace Errors.LA0201_Error;
// The aspect copies an internal attribute of its library into this assembly.
[Auditable]
public class Invoice
{
}
public static class Program
{
public static void Main()
{
// The method introduced into Invoice is not visible at compile time, so it is called with the dynamic keyword.
dynamic invoice = new Invoice();
Console.WriteLine( invoice.GetAuditTrail() );
}
}
error LA0201: Cannot copy the internal attribute "Errors.LA0201_Error.Auditing.AuditedAttribute" to "Errors.LA0201_Error.Invoice.GetAuditTrail", which is in another assembly. Make the attribute public, or remove it from the member of the aspect.
Resolution
- Make the attribute type
public, so that every assembly that uses the aspect can see it. - Otherwise, remove the attribute from the member of the aspect, or from the CopyCustomAttributesAttribute that selects it. The attributes of parameters, return values and generic parameters are always copied, so removing them is the only way to keep them internal.
In the following example, the [Audited] attribute is public, and the introduced method carries it.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0201_Fixed.Auditing;
// The attribute is public, so the assemblies that use the aspect can see it.
[AttributeUsage( AttributeTargets.Method )]
public sealed class AuditedAttribute : Attribute
{
}
[PSerializable]
public class AuditableAttribute : InstanceLevelAspect
{
[IntroduceMember]
[CopyCustomAttributes( typeof(AuditedAttribute) )]
[Audited]
public string GetAuditTrail() => $"Audit trail of {this.Instance!.GetType().Name}";
}
using System;
using Errors.LA0201_Fixed.Auditing;
namespace Errors.LA0201_Fixed;
// The aspect copies a public attribute of its library into this assembly.
[Auditable]
public class Invoice
{
}
public static class Program
{
public static void Main()
{
// The method introduced into Invoice is not visible at compile time, so it is called with the dynamic keyword.
dynamic invoice = new Invoice();
Console.WriteLine( invoice.GetAuditTrail() );
bool isAudited = typeof(Invoice).GetMethod( "GetAuditTrail" )!.IsDefined( typeof(AuditedAttribute), false );
Console.WriteLine( $"GetAuditTrail has [Audited]: {isAudited}" );
}
}
Audit trail of Invoice
GetAuditTrail has [Audited]: True
See Also
Reference
IntroduceMemberAttribute
CopyCustomAttributesAttribute
Other Resources
Introducing Interfaces, Methods, Properties and Events into Existing Classes