| Severity | Error |
| Reported by | Metalama.Framework |
| Message | In a template, 'dynamic' cannot be used as the type of a cast, 'as', 'is', or 'default' expression, as the type of a lambda parameter or return value, or as a type argument of a method. |
Cause
In a T# template, dynamic stands for a run-time type that's only known when Metalama expands the template. Metalama replaces each dynamic expression with code of the actual type. However, when dynamic is written as a type in the template, Metalama has no actual type to put in its place.
Metalama reports LAMA0250 when a template uses the dynamic type in one of the following places:
- the target type of a cast, for instance
(dynamic) value; - the type of an
isorasexpression; - the type of a
defaultexpression,default(dynamic); - the type of a parameter or the return type of a lambda expression;
- an explicit type argument of a generic method.
Using dynamic as an array element type, a generic type argument of a type, or a tuple element type is reported as LAMA0227.
In the following example, the aspect returns the default value of the return type when a feature is disabled, and the template uses default(dynamic).
1using Metalama.Framework.Aspects;
2
3namespace Doc.LAMA0250.Error;
4
5public class SkipIfDisabledAttribute : OverrideMethodAspect
6{
7 public override dynamic? OverrideMethod()
8 {
9 if ( !FeatureFlags.IsReportingEnabled )
10 {
11 // Error: default(dynamic) is not allowed in a template.
Error LAMA0250: In a template, 'dynamic' cannot be used as the type of a cast, 'as', 'is', or 'default' expression, as the type of a lambda parameter or return value, or as a type argument of a method.
12 return default(dynamic);
13 }
14
15 return meta.Proceed();
16 }
17}
18
1namespace Doc.LAMA0250.Error;
2
3public static class FeatureFlags
4{
5 public static bool IsReportingEnabled { get; set; }
6}
7
8internal class ReportService
9{
10 [SkipIfDisabled]
11 public int CountPendingReports() => 42;
12}
13
Resolution
Remove the dynamic type from the expression:
- To get the default value of the return type of the target method, use
meta.Default( meta.Target.Method.ReturnType ), as shown in the following example. - Instead of casting an expression to
dynamic, use an expression that's alreadydynamic, such as meta.Proceed() or the Value property of a parameter. To give a type to an expression, use WithType. - In lambdas and in type arguments, use the actual type, or build the code with the code model and ExpressionFactory.
1using Metalama.Framework.Aspects;
2
3namespace Doc.LAMA0250.Fixed;
4
5public class SkipIfDisabledAttribute : OverrideMethodAspect
6{
7 public override dynamic? OverrideMethod()
8 {
9 if ( !FeatureFlags.IsReportingEnabled )
10 {
11 // Fixed: meta.Default returns the default value of the return type.
12 return meta.Default( meta.Target.Method.ReturnType );
13 }
14
15 return meta.Proceed();
16 }
17}
18
Source Code
1namespace Doc.LAMA0250.Fixed;
2
3public static class FeatureFlags
4{
5 public static bool IsReportingEnabled { get; set; }
6}
7
8internal class ReportService
9{
10 [SkipIfDisabled]
11 public int CountPendingReports() => 42;
12}
13
Transformed Code
1namespace Doc.LAMA0250.Fixed;
2
3public static class FeatureFlags
4{
5 public static bool IsReportingEnabled { get; set; }
6}
7
8internal class ReportService
9{
10 [SkipIfDisabled]
11 public int CountPendingReports()
12 {
13 if (!FeatureFlags.IsReportingEnabled)
14 {
15 return default;
16 }
17
18 return 42;
19 }
20}
21