Open sandboxFocusImprove this doc

LAMA0901: The interface can only be implemented by the project that defines it

Severity Warning
Reported by Metalama.Extensions.Architecture
Message The '<Interface>' interface can only be implemented by the '<AssemblyName>' project or by another project that has access to its internals.

Cause

The InternalOnlyImplementAttribute aspect protects an interface from being implemented outside of its project. Once other projects implement an interface, you can no longer add members to it without breaking them. Other projects can still use the interface, for instance as a parameter or return type.

Metalama reports LAMA0901 when a type lists the interface among its base types, and the project of this type doesn't have access to the internals of the project that defines the interface. A project has access to these internals when it's the same project, or when the defining project grants it access with the InternalsVisibleToAttribute attribute.

In the message, <Interface> is the protected interface and <AssemblyName> is the name of the project that defines it.

In the following example, the IPaymentMethod interface is defined in a referenced project and marked with [InternalOnlyImplement]. The referencing project implements it in the GiftCardPayment class.

1namespace Doc.LAMA0901.Error;
2
3// Warning: IPaymentMethod can only be implemented in the project that defines it.
Warning LAMA0901: The 'IPaymentMethod' interface can only be implemented by the 'LAMA0901_Error' project or by another project that has access to its internals.

4internal class GiftCardPayment : IPaymentMethod
5{
6    public string Name => "Gift card";
7}
8
9internal class Checkout
10{
11    public IPaymentMethod GetPaymentMethod() => new GiftCardPayment();
12}
13
using Metalama.Extensions.Architecture.Aspects;

namespace Doc.LAMA0901.Error;

// Only the project that defines this interface can implement it.
[InternalOnlyImplement]
public interface IPaymentMethod
{
    string Name { get; }
}

public class CreditCardPayment : IPaymentMethod
{
    public string Name => "Credit card";
}

Resolution

Depending on your intent, do one of the following:

  • Move the implementation to the project that defines the interface, and use it from the other project. The following example does this.
  • If the implementing project is trusted, for instance a test project or a companion project of the same product, grant it access to the internals of the defining project with the InternalsVisibleTo assembly attribute.
  • If you own the interface and want other projects to implement it, remove the [InternalOnlyImplement] attribute.

1namespace Doc.LAMA0901.Fixed;
2
3internal class Checkout
4{
5    // Fixed: the class uses the implementation provided by the project that defines the interface.
6    public IPaymentMethod GetPaymentMethod() => new GiftCardPayment();
7}
8
using Metalama.Extensions.Architecture.Aspects;

namespace Doc.LAMA0901.Fixed;

// Only the project that defines this interface can implement it.
[InternalOnlyImplement]
public interface IPaymentMethod
{
    string Name { get; }
}

public class CreditCardPayment : IPaymentMethod
{
    public string Name => "Credit card";
}

// Fixed: the implementation is moved to the project that defines the interface.
public class GiftCardPayment : IPaymentMethod
{
    public string Name => "Gift card";
}

See also