| Severity | Warning |
| Reported by | PostSharp |
| Message | Interface <Interface> cannot be implemented by <ImplementingType> because of the [InternalImplement] constraint. |
Cause
The InternalImplementAttribute constraint lets other assemblies use a public interface but not implement it, so that its author can add members to it later without breaking their code. When PostSharp processes an assembly that references the interface, it reports AR0101 on each type of this assembly that derives from the interface. A type is allowed when the assembly of the interface grants access to the implementing assembly with InternalsVisibleToAttribute. The check runs only when the implementing project is processed by PostSharp.
AR0101 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 shipping library marks IShippingRate as [InternalImplement] and provides its implementations through ShippingRates:
using System;
using PostSharp.Constraints;
namespace Errors.AR0101_Error.Shipping;
// The shipping library adds members to this interface in new versions, so only the library implements it.
[InternalImplement]
public interface IShippingRate
{
string Name { get; }
decimal GetCost( decimal weight );
}
public static class ShippingRates
{
public static IShippingRate PerKilogram( string name, decimal pricePerKilogram ) => new PerKilogramRate( name, pricePerKilogram );
private sealed class PerKilogramRate : IShippingRate
{
private readonly decimal _pricePerKilogram;
public PerKilogramRate( string name, decimal pricePerKilogram )
{
this.Name = name;
this._pricePerKilogram = pricePerKilogram;
}
public string Name { get; }
public decimal GetCost( decimal weight ) => weight * this._pricePerKilogram;
}
}
The application, in another assembly, implements IShippingRate in ExpressRate:
using System;
using Errors.AR0101_Error.Shipping;
namespace Errors.AR0101_Error;
// This class implements IShippingRate, which only the shipping library can implement.
public class ExpressRate : IShippingRate
{
public string Name => "Express";
public decimal GetCost( decimal weight ) => weight * 4.5m;
}
public static class Program
{
public static void Main()
{
IShippingRate rate = new ExpressRate();
Console.WriteLine( $"{rate.Name}: {rate.GetCost( 2m ):0.00}" );
}
}
warning AR0101: AR0101_Error.cs(7,14): Interface Errors.AR0101_Error.Shipping.IShippingRate cannot be implemented by Errors.AR0101_Error.ExpressRate because of the [InternalImplement] constraint.
Resolution
- Use the implementations that the library of the interface provides, through its factory methods or its public classes, instead of implementing the interface.
- When the implementing assembly is a trusted part of the same product, such as a test project, add an InternalsVisibleToAttribute to the assembly of the interface.
- When the implementation is an exception that you accept, suppress the warning on the implementing type with SuppressWarningAttribute. Your type then breaks when the library adds a member to the interface. The suppression does not work when the severity of the constraint is Error.
In the following example, the application gets its rate from ShippingRates.PerKilogram.
using System;
using Errors.AR0101_Fixed.Shipping;
namespace Errors.AR0101_Fixed;
public static class Program
{
public static void Main()
{
// The shipping library creates the rate.
IShippingRate rate = ShippingRates.PerKilogram( "Express", 4.5m );
Console.WriteLine( $"{rate.Name}: {rate.GetCost( 2m ):0.00}" );
}
}
Express: 9.00
See Also
Reference
InternalImplementAttribute
SuppressWarningAttribute
Other Resources