| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The aspect '<Aspect>' cannot be a value type. Declare it as a class. |
Cause
An aspect is a type that implements the IAspect interface. Metalama creates and manages aspect instances as objects, and the APIs that add aspects, such as AddAspect, accept only reference types. For this reason, an aspect must be a class.
Metalama reports LAMA0278 when a struct or a record struct implements IAspect or one of its generic variants.
In the following example, the LogAspect aspect is declared as a struct.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using Metalama.Framework.Eligibility;
4using System;
5
6namespace Doc.LAMA0278.Error;
7
8// Error: an aspect must be a class, not a struct.
Error LAMA0278: The aspect 'LogAspect' cannot be a value type. Declare it as a class.
9internal struct LogAspect : IAspect<IMethod>
10{
11 public void BuildAspect( IAspectBuilder<IMethod> builder )
12 {
13 builder.Override( nameof(this.OverrideMethod) );
14 }
15
16 public void BuildEligibility( IEligibilityBuilder<IMethod> builder ) { }
17
18 [Template]
19 private dynamic? OverrideMethod()
20 {
21 Console.WriteLine( $"Executing {meta.Target.Method}." );
22
23 return meta.Proceed();
24 }
25}
26
1namespace Doc.LAMA0278.Error;
2
3internal class Calculator
4{
5 public int Add( int a, int b ) => a + b;
6}
7
Resolution
Declare the aspect as a class. In the following example, the aspect is a class, so a fabric can add it to the methods of Calculator.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using Metalama.Framework.Eligibility;
4using System;
5
6namespace Doc.LAMA0278.Fixed;
7
8// Fixed: the aspect is a class.
9internal class LogAspect : IAspect<IMethod>
10{
11 public void BuildAspect( IAspectBuilder<IMethod> builder )
12 {
13 builder.Override( nameof(this.OverrideMethod) );
14 }
15
16 public void BuildEligibility( IEligibilityBuilder<IMethod> builder ) { }
17
18 [Template]
19 private dynamic? OverrideMethod()
20 {
21 Console.WriteLine( $"Executing {meta.Target.Method}." );
22
23 return meta.Proceed();
24 }
25}
26
Source Code
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Fabrics;
3
4namespace Doc.LAMA0278.Fixed;
5
6internal class Calculator
7{
8 public int Add( int a, int b ) => a + b;
9
10 private class Fabric : TypeFabric
11 {
12 public override void AmendType( ITypeAmender amender )
13 {
14 // Because LogAspect is now a class, it can be added to the methods of the type.
15 amender.SelectMany( t => t.Methods ).AddAspect<LogAspect>();
16 }
17 }
18}
19
Transformed Code
1using System;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Fabrics;
4
5namespace Doc.LAMA0278.Fixed;
6
7
8#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
9
10internal class Calculator
11{
12 public int Add(int a, int b)
13 {
14 Console.WriteLine("Executing Calculator.Add(int, int).");
15 return a + b;
16 }
17
18
19#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
20
21 private class Fabric : TypeFabric
22 {
23 public override void AmendType(ITypeAmender amender) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
24 }
25
26#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
27
28
29}
30
31#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
32
33
34