| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The type '<Type>' is forbidden in a template: 'dynamic' cannot be used as a generic argument type, an array element type, a tuple element type or a ref type. |
Cause
In a T# template, dynamic stands for a run-time value or type that Metalama doesn't know when it compiles the aspect. When Metalama expands the template, it replaces each dynamic expression with the code of the actual expression. This works only when dynamic is used directly as the type of an expression, a local variable, or a template return value.
Metalama reports LAMA0227 when a template uses dynamic as a component of another type: as a generic argument (List<dynamic>), as an array element type (dynamic[], new dynamic[5]), as a tuple element type ((dynamic, int)), or with ref (ref dynamic). The placeholder of the message is the offending type, as written in the template.
In the following example, the aspect copies the argument values of the target method, obtained with meta.Target.Parameters.ToValueArray(), into a List<dynamic?>.
1using Metalama.Framework.Aspects;
2using System;
3using System.Collections.Generic;
4
5namespace Doc.LAMA0227.Error;
6
7public class LogArgumentsAttribute : OverrideMethodAspect
8{
9 public override dynamic? OverrideMethod()
10 {
11 // Error: dynamic cannot be used as a generic argument in a template.
Error LAMA0227: The type 'List<dynamic?>' is forbidden in a template: 'dynamic' cannot be used as a generic argument type, an array element type, a tuple element type or a ref type.
12 var values = new List<dynamic?>( meta.Target.Parameters.ToValueArray() );
13
14 Console.WriteLine( $"{meta.Target.Method.Name}({string.Join( ", ", values )})" );
15
16 return meta.Proceed();
17 }
18}
19
1namespace Doc.LAMA0227.Error;
2
3internal class Calculator
4{
5 [LogArguments]
6 public int Add( int a, int b ) => a + b;
7}
8
Resolution
Replace dynamic with a type that the generated code can use:
- Use
objectorobject?when the values only need to be stored or passed along, as in the following example. Adynamicexpression converts implicitly toobject. - Use the actual type when it's known, or a generic template parameter when it depends on the target declaration.
- To pass all arguments of the target method as an array, use
meta.Target.Parameters.ToValueArray()directly. It generates anobject[]expression.
1using Metalama.Framework.Aspects;
2using System;
3using System.Collections.Generic;
4
5namespace Doc.LAMA0227.Fixed;
6
7public class LogArgumentsAttribute : OverrideMethodAspect
8{
9 public override dynamic? OverrideMethod()
10 {
11 // Fixed: the list stores the argument values as object.
12 var values = new List<object?>( meta.Target.Parameters.ToValueArray() );
13
14 Console.WriteLine( $"{meta.Target.Method.Name}({string.Join( ", ", values )})" );
15
16 return meta.Proceed();
17 }
18}
19
1namespace Doc.LAMA0227.Fixed;
2
3internal class Calculator
4{
5 [LogArguments]
6 public int Add( int a, int b ) => a + b;
7}
8
1using System;
2using System.Collections.Generic;
3
4namespace Doc.LAMA0227.Fixed;
5
6internal class Calculator
7{
8 [LogArguments]
9 public int Add(int a, int b)
10 {
11 var values = new List<object?>(new object[] { a, b });
12 Console.WriteLine($"Add({string.Join(", ", values)})");
13 return a + b;
14 }
15}
16