| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The template '<Template>' cannot be called because it is abstract or marked with [Template(IsEmpty = true)]. Call a template that has an implementation instead, for example a virtual template with a default implementation. |
Cause
When a template calls an auxiliary template, Metalama expands the body of the called template into the generated code. An abstract template has no body, and a template marked with [Template(IsEmpty = true)] is only a placeholder meant to be overridden, so neither can be expanded.
Metalama reports LAMA0279 when the call to an auxiliary template resolves to such a template. The typical situations are:
- An aspect base class calls one of its own abstract templates. Metalama reports the error even if every derived aspect overrides the template.
- A template calls a template through the interface that declares it, for instance after a cast to the interface.
- A template calls an empty template of a base class, for instance
base.OverrideAsyncMethod()in an aspect derived from OverrideMethodAspect, or OverrideAsyncMethod() when the aspect doesn't override it.
In the following example, the abstract aspect class LogAttributeBase calls its abstract template LogEntry, which is implemented by the derived aspect ConsoleLogAttribute.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0279.Error;
5
6public abstract class LogAttributeBase : OverrideMethodAspect
7{
8 public override dynamic? OverrideMethod()
9 {
10 // Error: LogEntry is an abstract template, so it can't be called.
Error LAMA0279: The template 'LogAttributeBase.LogEntry()' cannot be called because it is abstract or marked with [Template(IsEmpty = true)]. Call a template that has an implementation instead, for example a virtual template with a default implementation.
11 this.LogEntry();
12
13 return meta.Proceed();
14 }
15
16 [Template]
17 protected abstract void LogEntry();
18}
19
20public class ConsoleLogAttribute : LogAttributeBase
21{
22 protected override void LogEntry()
23 {
24 Console.WriteLine( $"Executing {meta.Target.Method}." );
25 }
26}
27
1namespace Doc.LAMA0279.Error;
2
3internal class Calculator
4{
5 [ConsoleLog]
6 public int Add( int a, int b ) => a + b;
7}
8
Resolution
Depending on the situation, do one of the following:
- In an aspect base class, make the template
virtualinstead ofabstract, and give it a default implementation, which can be empty. Derived aspects can still override it, and Metalama expands the override. The following example uses this fix. - When you call a template declared in an interface, call it on the aspect class that implements it.
- Don't call an empty template of the base class. Write the code you need in your own template instead.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0279.Fixed;
5
6public abstract class LogAttributeBase : OverrideMethodAspect
7{
8 public override dynamic? OverrideMethod()
9 {
10 this.LogEntry();
11
12 return meta.Proceed();
13 }
14
15 // Fixed: the template is virtual and has an empty default implementation.
16 [Template]
17 protected virtual void LogEntry() { }
18}
19
20public class ConsoleLogAttribute : LogAttributeBase
21{
22 protected override void LogEntry()
23 {
24 Console.WriteLine( $"Executing {meta.Target.Method}." );
25 }
26}
27
Source Code
1namespace Doc.LAMA0279.Fixed;
2
3internal class Calculator
4{
5 [ConsoleLog]
6 public int Add( int a, int b ) => a + b;
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0279.Fixed;
4
5internal class Calculator
6{
7 [ConsoleLog]
8 public int Add(int a, int b)
9 {
10 Console.WriteLine("Executing Calculator.Add(int, int).");
11 return a + b;
12 }
13}
14