| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The 'dynamic' keyword cannot be used in the local variable '<Variable>' because it is initialized with a target-typed expression (such as 'default' or 'null'). Initialize the variable with an expression of type 'dynamic', for example 'meta.Default( type )'. |
Cause
In a T# template, dynamic stands for a run-time type that's only known when Metalama expands the template. Metalama infers the actual type of a dynamic local variable from its initializer. A target-typed expression has no type of its own: it takes the type of its destination, so it can't give a type to the variable.
Metalama reports LAMA0225 when a template initializes a local variable of type dynamic (or dynamic?) with a target-typed expression: the null or default literal, a throw expression, or a stackalloc expression, possibly in parentheses. The placeholder of the message is the name of the variable.
In the following example, the aspect returns the default value of the return type when the method throws an exception, and the template initializes result with null.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0225.Error;
5
6public class ReturnDefaultOnExceptionAttribute : OverrideMethodAspect
7{
8 public override dynamic? OverrideMethod()
9 {
10 // Error: null is target-typed, so it can't initialize a variable of type dynamic.
Error LAMA0225: The 'dynamic' keyword cannot be used in the local variable 'result' because it is initialized with a target-typed expression (such as 'default' or 'null'). Initialize the variable with an expression of type 'dynamic', for example 'meta.Default( type )'.
11 dynamic? result = null;
12
13 try
14 {
15 result = meta.Proceed();
16 }
17 catch ( Exception e )
18 {
19 Console.WriteLine( $"{meta.Target.Method.Name} failed: {e.Message}" );
20 }
21
22 return result;
23 }
24}
25
1namespace Doc.LAMA0225.Error;
2
3internal class Calculator
4{
5 [ReturnDefaultOnException]
6 public int Divide( int a, int b ) => a / b;
7}
8
Resolution
Initialize the variable with an expression of type dynamic. 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.
Casting the initializer doesn't help: a cast to dynamic isn't allowed in templates, and a cast to another type doesn't produce a dynamic expression. If you know the type of the variable, declare it with this type instead of dynamic.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0225.Fixed;
5
6public class ReturnDefaultOnExceptionAttribute : OverrideMethodAspect
7{
8 public override dynamic? OverrideMethod()
9 {
10 // Fixed: meta.Default returns the default value of the return type as a dynamic expression.
11 dynamic? result = meta.Default( meta.Target.Method.ReturnType );
12
13 try
14 {
15 result = meta.Proceed();
16 }
17 catch ( Exception e )
18 {
19 Console.WriteLine( $"{meta.Target.Method.Name} failed: {e.Message}" );
20 }
21
22 return result;
23 }
24}
25
1namespace Doc.LAMA0225.Fixed;
2
3internal class Calculator
4{
5 [ReturnDefaultOnException]
6 public int Divide( int a, int b ) => a / b;
7}
8
1using System;
2
3namespace Doc.LAMA0225.Fixed;
4
5internal class Calculator
6{
7 [ReturnDefaultOnException]
8 public int Divide(int a, int b)
9 {
10 var result = default(int);
11 try
12 {
13 result = a / b;
14 }
15 catch (Exception e)
16 {
17 Console.WriteLine($"Divide failed: {e.Message}");
18 }
19
20 return result;
21 }
22}
23