Open sandboxFocusImprove this doc

LAMA0513: The type arguments of the generic interface aren't specified

Severity Error
Reported by Metalama.Framework
Message The aspect '<AspectType>' cannot implement interface type '<InterfaceType>' in the type '<TargetType>' because it is a canonical generic instance. Specify all type arguments of the generic interface type. If needed, use type parameters of the target type.

Cause

A type can only implement a constructed generic interface, such as IEquatable<Product>, where every type argument is known. When you pass an unbound generic type such as typeof(IEntity<>) to ImplementInterface, Metalama receives the canonical generic instance of the interface, whose type arguments are its own type parameters, for instance IEntity<T>. This type can't be added to the base list of the target type.

Metalama reports LAMA0513 when the interface passed to ImplementInterface is such a canonical generic instance.

In the following example, the Entity aspect passes typeof(IEntity<>) without a type argument.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3
4namespace Doc.LAMA0513.Error;
5
6// Marker interface that identifies entity types in the repository.
7public interface IEntity<T> { }
8
9public class EntityAttribute : TypeAspect
10{
11    public override void BuildAspect( IAspectBuilder<INamedType> builder )
12    {
13        // The type argument of IEntity<T> isn't specified.
14        builder.ImplementInterface( typeof(IEntity<>) );
15    }
16}
17
1namespace Doc.LAMA0513.Error;
2
3// Error: the aspect implements IEntity<T> without specifying the type argument.
4[Entity]
Error LAMA0513: The aspect 'Entity' cannot implement interface type 'IEntity<T>' in the type 'Product' because it is a canonical generic instance. Specify all type arguments of the generic interface type. If needed, use type parameters of the target type.

5internal partial class Product
6{
7    public decimal Price { get; set; }
8}
9

Resolution

Specify all type arguments of the interface:

  • If the type arguments are known in advance, pass a closed type such as typeof(IEntity<Customer>).
  • Otherwise, build the constructed type with the code model: get the generic interface with GetNamedTypeByReflectionType and call MakeGenericInstance with the type arguments, for instance the target type itself. If the target type is generic, you can pass its type parameters.

In the following example, the aspect implements IEntity<Product> by passing the target type as the type argument.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3
4namespace Doc.LAMA0513.Fixed;
5
6// Marker interface that identifies entity types in the repository.
7public interface IEntity<T> { }
8
9public class EntityAttribute : TypeAspect
10{
11    public override void BuildAspect( IAspectBuilder<INamedType> builder )
12    {
13        // The target type is given as the type argument of IEntity<T>.
14        var interfaceType = builder.Target.Compilation.Factory
15            .GetNamedTypeByReflectionType( typeof(IEntity<>) )
16            .MakeGenericInstance( builder.Target );
17
18        builder.ImplementInterface( interfaceType );
19    }
20}
21
Source Code
1namespace Doc.LAMA0513.Fixed;
2
3// Fixed: the aspect implements IEntity<Product>.
4[Entity]
5internal partial class Product
6{
7    public decimal Price { get; set; }
8}
9
Transformed Code
1namespace Doc.LAMA0513.Fixed;
2
3// Fixed: the aspect implements IEntity<Product>.
4[Entity]
5internal partial class Product : IEntity<Product>
6{
7    public decimal Price { get; set; }
8}
9

See also