Open sandboxFocusImprove this doc

LAMA0238: Only templates can use the dynamic type in compile-time code

Severity Error
Reported by Metalama.Framework
Message '<Member>' cannot use the 'dynamic' type because it is not a template and its declaring type '<DeclaringType>' is <DeclaringTypeScope>. Only templates and members of run-time-only types can use the 'dynamic' type.

Cause

In Metalama, the dynamic type has a special meaning: in a template, it represents a run-time value, such as the return value of meta.Proceed(). Outside of templates, compile-time code executes during compilation, where no run-time value exists, so dynamic has no meaning there.

Metalama reports LAMA0238 when a field that isn't a template uses the dynamic type, alone or in a constructed type like dynamic[] or List<dynamic>, and the field belongs to a type that isn't run-time-only, for instance an aspect, a fabric, or a type marked with CompileTimeAttribute. The last placeholder of the message gives the scope of the declaring type, for instance run-time-or-compile-time for an aspect.

In the following example, the Log aspect stores its category in a field of type dynamic.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0238.Error;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    // Error: a field of an aspect cannot be of type dynamic because it is not a template.
    Error LAMA0238: 'LogAttribute._category' cannot use the 'dynamic' type because it is not a template and its declaring type 'LogAttribute' is run-time-or-compile-time. Only templates and members of run-time-only types can use the 'dynamic' type.

9    private readonly dynamic _category = "General";
10
11    public override dynamic? OverrideMethod()
12    {
13        Console.WriteLine( $"[{this._category}] Entering {meta.Target.Method}." );
14
15        return meta.Proceed();
16    }
17}
18
1namespace Doc.LAMA0238.Error;
2
3internal class Calculator
4{
5    [Log]
6    public int Add( int a, int b ) => a + b;
7}
8

Resolution

Depending on your intent, do one of the following:

  • If the field holds a compile-time value, give it a concrete type. The value can still be used in templates, where Metalama inserts it into the generated code. The following example uses this fix.
  • If the field must hold a run-time expression built at compile time, use IExpression instead of dynamic, and use its Value property in templates.
  • If you want to introduce the field into the target type, add the IntroduceAttribute attribute, so that the field becomes a template.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0238.Fixed;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    // Fixed: the field has a concrete type, so its value is known at compile time.
9    private readonly string _category = "General";
10
11    public override dynamic? OverrideMethod()
12    {
13        Console.WriteLine( $"[{this._category}] Entering {meta.Target.Method}." );
14
15        return meta.Proceed();
16    }
17}
18
Source Code
1namespace Doc.LAMA0238.Fixed;
2


3internal class Calculator
4{
5    [Log]
6    public int Add( int a, int b ) => a + b;
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0238.Fixed;
4
5internal class Calculator
6{
7    [Log]
8    public int Add(int a, int b)
9    {
10        Console.WriteLine("[General] Entering Calculator.Add(int, int).");
11        return a + b;
12    }
13}
14

See also