Open sandboxFocusImprove this doc

LAMA0273: A template can only be referenced in a direct call

Severity Error
Reported by Metalama.Framework
Message The template '<Template>' can only be referenced in a direct call. It cannot be assigned to a delegate, passed as an argument, or called with the '?.' operator.

Cause

A template can call an auxiliary template, and the code generated by the auxiliary template expands at the call site. This expansion happens at compile time, so Metalama must know statically which template is called. That's why the only accepted forms are Template(...) and expression.Template(...).

Metalama reports LAMA0273 when a template references an auxiliary template in any other way, for example:

  • by assigning the template to a delegate or a variable;
  • by passing the template as an argument to a method;
  • by calling it with the conditional access operator ?..

The <Template> placeholder is the referenced template.

In the following example, the Log aspect stores the LogEntry template in a variable before calling it.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0273.Error;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        // Error: the LogEntry template is assigned to a delegate instead of being invoked.
        Error LAMA0273: The template 'LogAttribute.LogEntry()' can only be referenced in a direct call. It cannot be assigned to a delegate, passed as an argument, or called with the '?.' operator.

11        var logEntry = LogEntry;
12        logEntry();
13
14        return meta.Proceed();
15    }
16
17    [Template]
18    private void LogEntry()
19    {
20        Console.WriteLine( $"Entering {meta.Target.Method}." );
21    }
22}
23
1namespace Doc.LAMA0273.Error;
2
3internal class Calculator
4{
5    [Log]
6    public int Add( int a, int b ) => a + b;
7}
8

Resolution

Call the auxiliary template directly, as a stand-alone statement. If the call must depend on a condition, put the direct call in a compile-time if statement instead of using ?..

If you need to pass a template call as a value, for example to let another template decide when to call it, use a TemplateInvocation and invoke it with meta.InvokeTemplate.

In the following example, the LogEntry template is called directly.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0273.Fixed;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        // Fixed: the LogEntry template is invoked directly.
11        LogEntry();
12
13        return meta.Proceed();
14    }
15
16    [Template]
17    private void LogEntry()
18    {
19        Console.WriteLine( $"Entering {meta.Target.Method}." );
20    }
21}
22
Source Code
1namespace Doc.LAMA0273.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.LAMA0273.Fixed;
4
5internal class Calculator
6{
7    [Log]
8    public int Add(int a, int b)
9    {
10        Console.WriteLine("Entering Calculator.Add(int, int).");
11        return a + b;
12    }
13}
14

See also