| Severity | Error |
| Reported by | Metalama.Framework |
| Message | A compile-time value cannot be converted to a run-time value because the type '<Type>' is not supported. Use a supported type or a type that implements the IExpressionBuilder interface. |
Cause
When a template uses a compile-time value in a run-time context, for instance in a return statement, as an argument of a run-time method, or in a call to meta.RunTime, Metalama evaluates the value at compile time and generates C# code that creates an equivalent value at run time. This conversion is only possible for a limited set of types: literals, enums, one-dimensional arrays, tuples, reflection objects, List, Dictionary, and a few others. It's also possible for any type that implements the IExpressionBuilder interface.
Metalama reports LAMA0200 when it compiles the template and finds that the type of the value isn't supported. It checks the type arguments and array element types too, so <Type> can be a type argument rather than the type of the whole value: for a Dictionary<string, MethodOverloadCount>, <Type> is MethodOverloadCount.
When the static type of the compile-time value is object, Metalama can't check it when it compiles the template. It then reports LAMA0200 when it expands the template, and <Type> is the actual type of the value.
In the following example, the aspect computes a dictionary of MethodOverloadCount objects at compile time and returns it from an introduced method. The MethodOverloadCount class exists at both compile time and run time, but Metalama doesn't know how to generate the code that creates an instance of it.
1using Metalama.Framework.Aspects;
2using System.Collections.Generic;
3using System.Linq;
4
5namespace Doc.LAMA0200.Error;
6
7public class MethodOverloadCountAttribute : TypeAspect
8{
9 // Introduces a method that returns the number of overloads of each method.
10 [Introduce]
11 public Dictionary<string, MethodOverloadCount> GetMethodOverloadCount()
12 {
13 var dictionary = meta.Target.Type.Methods
14 .GroupBy( m => m.Name )
15 .Select( g => new MethodOverloadCount( g.Key, g.Count() ) )
16 .ToDictionary( m => m.Name, m => m );
17
18 // Error: MethodOverloadCount can't be converted to a run-time value.
Error LAMA0200: A compile-time value cannot be converted to a run-time value because the type 'MethodOverloadCount' is not supported. Use a supported type or a type that implements the IExpressionBuilder interface.
19 return dictionary;
20 }
21}
22
23// This class exists both at compile time and at run time.
24[RunTimeOrCompileTime]
25public class MethodOverloadCount
26{
27 public MethodOverloadCount( string name, int count )
28 {
29 this.Name = name;
30 this.Count = count;
31 }
32
33 public string Name { get; }
34
35 public int Count { get; }
36}
37
1namespace Doc.LAMA0200.Error;
2
3[MethodOverloadCount]
4public partial class OrderService
5{
6 public void Submit() { }
7
8 public void Submit( int priority ) { }
9
10 public void Cancel() { }
11}
12
Resolution
Do one of the following:
- If you own the type, implement the IExpressionBuilder interface. Its ToExpression() method returns a C# expression that creates an equivalent value at run time. Use the ExpressionBuilder class to build it.
- Convert the value to a supported type before you use it in run-time code, for instance a list of strings or a tuple.
- Use only the supported members of the value, for instance a
stringproperty, instead of the whole object.
In the following example, MethodOverloadCount implements IExpressionBuilder, so Metalama generates a call to its constructor for each item of the dictionary.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using Metalama.Framework.Code.SyntaxBuilders;
4using System.Collections.Generic;
5using System.Linq;
6
7namespace Doc.LAMA0200.Fixed;
8
9public class MethodOverloadCountAttribute : TypeAspect
10{
11 // Introduces a method that returns the number of overloads of each method.
12 [Introduce]
13 public Dictionary<string, MethodOverloadCount> GetMethodOverloadCount()
14 {
15 var dictionary = meta.Target.Type.Methods
16 .GroupBy( m => m.Name )
17 .Select( g => new MethodOverloadCount( g.Key, g.Count() ) )
18 .ToDictionary( m => m.Name, m => m );
19
20 return dictionary;
21 }
22}
23
24// This class exists both at compile time and at run time.
25// Fixed: it implements IExpressionBuilder, so Metalama can convert it to a run-time value.
26[RunTimeOrCompileTime]
27public class MethodOverloadCount : IExpressionBuilder
28{
29 public MethodOverloadCount( string name, int count )
30 {
31 this.Name = name;
32 this.Count = count;
33 }
34
35 public string Name { get; }
36
37 public int Count { get; }
38
39 public IExpression ToExpression()
40 {
41 var builder = new ExpressionBuilder();
42 builder.AppendVerbatim( "new " );
43 builder.AppendTypeName( typeof(MethodOverloadCount) );
44 builder.AppendVerbatim( "(" );
45 builder.AppendLiteral( this.Name );
46 builder.AppendVerbatim( ", " );
47 builder.AppendLiteral( this.Count );
48 builder.AppendVerbatim( ")" );
49
50 return builder.ToExpression();
51 }
52}
53
1namespace Doc.LAMA0200.Fixed;
2
3[MethodOverloadCount]
4public partial class OrderService
5{
6 public void Submit() { }
7
8 public void Submit( int priority ) { }
9
10 public void Cancel() { }
11}
12
1using System.Collections.Generic;
2
3namespace Doc.LAMA0200.Fixed;
4
5[MethodOverloadCount]
6public partial class OrderService
7{
8 public void Submit() { }
9
10 public void Submit(int priority) { }
11
12 public void Cancel() { }
13
14 public Dictionary<string, MethodOverloadCount> GetMethodOverloadCount()
15 {
16 return new Dictionary<string, MethodOverloadCount>
17 {
18 {
19 "Submit",
20 new MethodOverloadCount("Submit", 2)
21 },
22 {
23 "Cancel",
24 new MethodOverloadCount("Cancel", 1)
25 }
26 };
27 }
28}
29