| Severity | Warning |
| Reported by | PostSharp |
| Message | Cannot use <ReferencedKind> <ReferencedDeclaration> in <ReferencingKind> <ReferencingDeclaration> because the [Internal] constraint restricts it to its own assembly and to the assemblies that this assembly grants access to with [InternalsVisibleTo]. |
Cause
The InternalAttribute constraint marks a declaration that must be public for technical reasons as an implementation detail of its assembly. When PostSharp processes another assembly, it checks the references of this assembly to the declaration, and reports AR0105 on each method or type that uses it: it calls the method or constructor, reads the field, derives from the type, uses the type in a signature, or applies the custom attribute. A reference is allowed when the assembly of the declaration grants access to the referencing assembly with InternalsVisibleToAttribute.
<ReferencingDeclaration> is the declaration that holds the reference, and the message is reported at its location, not at the line of the reference. The check runs only when the referencing project is processed by PostSharp.
AR0105 is a warning by default. Its severity comes from the Severity property of the constraint, which you can set to Error.
In the following example, a payment library marks CardTokenizer.Tokenize as [Internal]:
using System;
using PostSharp.Constraints;
namespace Errors.AR0105_Error.Payments;
public static class CardTokenizer
{
// PaymentGateway needs this method to be public, but it is not part of the API of the library.
[Internal]
public static string Tokenize( string cardNumber ) => "tok_" + cardNumber.Substring( cardNumber.Length - 4 );
}
public class PaymentGateway
{
public string Charge( string cardNumber, decimal amount )
{
return $"Charged {amount:0.00} to {CardTokenizer.Tokenize( cardNumber )}";
}
}
The application, in another assembly, calls CardTokenizer.Tokenize directly:
using System;
using Errors.AR0105_Error.Payments;
namespace Errors.AR0105_Error;
public class CheckoutService
{
// This method calls CardTokenizer.Tokenize, an implementation detail of the payment library.
public string Checkout( string cardNumber, decimal amount )
{
string token = CardTokenizer.Tokenize( cardNumber );
return $"Order paid with {token}: {new PaymentGateway().Charge( cardNumber, amount )}";
}
}
public static class Program
{
public static void Main()
{
Console.WriteLine( new CheckoutService().Checkout( "4111111111111111", 42m ) );
}
}
warning AR0105: AR0105_Error.cs(9,19): Cannot use Method Errors.AR0105_Error.Payments.CardTokenizer.Tokenize(System.String) in method Errors.AR0105_Error.CheckoutService.Checkout(System.String, System.Decimal) because the [Internal] constraint restricts it to its own assembly and to the assemblies that this assembly grants access to with [InternalsVisibleTo].
Resolution
- Use the public API of the library instead of the internal declaration.
- When the referencing assembly is a trusted part of the same product, such as a test project, add an InternalsVisibleToAttribute to the assembly of the declaration.
- When the reference is an exception that you accept, suppress the warning on the referencing declaration with SuppressWarningAttribute. This does not work when the severity of the constraint is Error.
In the following example, the application charges the card through PaymentGateway, which calls CardTokenizer.Tokenize inside the library.
using System;
using Errors.AR0105_Fixed.Payments;
namespace Errors.AR0105_Fixed;
public class CheckoutService
{
// This method uses only the public API of the payment library.
public string Checkout( string cardNumber, decimal amount )
{
return $"Order paid: {new PaymentGateway().Charge( cardNumber, amount )}";
}
}
public static class Program
{
public static void Main()
{
Console.WriteLine( new CheckoutService().Checkout( "4111111111111111", 42m ) );
}
}
Order paid: Charged 42.00 to tok_1111
See Also
Reference
InternalAttribute
SuppressWarningAttribute
Other Resources
Controlling Component Visibility Beyond Private and Internal