| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The type '<AspectClass>' is not a valid aspect type because it is generic and not abstract. Only abstract aspect types can be generic. |
Cause
When Metalama loads the aspect classes of a project, it checks each of them. Metalama doesn't support aspect classes with type parameters, so it reports LAMA0059 for every non-abstract aspect class that's generic, whether or not the aspect is used. Since C# 11 allows generic attributes, this typically happens when you write an aspect meant to be used as [MyAspect<int>].
An abstract generic class is accepted, because Metalama never instantiates it directly. In the message, <AspectClass> is the generic aspect class.
In the following example, the Id aspect is generic so that you can choose the type of the introduced Id property.
1using Metalama.Framework.Aspects;
2
3namespace Doc.LAMA0059.Error;
4
5// Error: a non-abstract aspect class cannot be generic.
Error LAMA0059: The type 'IdAttribute<T>' is not a valid aspect type because it is generic and not abstract. Only abstract aspect types can be generic.
6public class IdAttribute<T> : TypeAspect
7{
8 [Introduce]
9 public T? Id { get; set; }
10}
11
1namespace Doc.LAMA0059.Error;
2
3[Id<int>]
4internal partial class Order
5{
6 public string? Customer { get; set; }
7}
8
Resolution
Remove the type parameters from the aspect class, and pass the information in another way:
- Pass the type as a Type argument of the aspect constructor, for example
[Id( typeof(int) )], and convert it to an IType with GetType inBuildAspect. Then use the programmatic advice API, such as IntroduceAutomaticProperty, instead of declarative [Introduce] members. - Alternatively, keep a generic base class but make it
abstract, and derive one non-generic aspect class for each type argument you need.
In the following example, the type of the property is passed with typeof, and the aspect introduces the property programmatically.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0059.Fixed;
6
7// Fixed: the aspect class isn't generic; the type is passed as a constructor argument.
8public class IdAttribute : TypeAspect
9{
10 private readonly Type _idType;
11
12 public IdAttribute( Type idType )
13 {
14 this._idType = idType;
15 }
16
17 public override void BuildAspect( IAspectBuilder<INamedType> builder )
18 {
19 builder.IntroduceAutomaticProperty(
20 "Id",
21 TypeFactory.GetType( this._idType ),
22 buildProperty: p => p.Accessibility = Accessibility.Public );
23 }
24}
25
1namespace Doc.LAMA0059.Fixed;
2
3// Fixed: the type of the property is given with typeof.
4[Id( typeof(int) )]
5internal partial class Order
6{
7 public string? Customer { get; set; }
8}
9
1namespace Doc.LAMA0059.Fixed;
2
3// Fixed: the type of the property is given with typeof.
4[Id(typeof(int))]
5internal partial class Order
6{
7 public string? Customer { get; set; }
8
9
10 public int Id { get; set; }
11}
12