Open sandboxFocusImprove this doc

LAMA0274: A template must be declared in an aspect, a fabric, or a template provider

Severity Error
Reported by Metalama.Framework
Message The template '<Template>' is contained in '<ContainingType>', which is not an aspect, a fabric, or a type implementing ITemplateProvider.

Cause

Templates, that is, members marked with a template attribute such as [Template] or [Introduce], can only be declared in an aspect, in a fabric, or in a type that implements the ITemplateProvider interface.

Metalama reports LAMA0274 when a template is declared in any other type. The <Template> placeholder is the template and <ContainingType> is the type that contains it. This often happens when you move auxiliary templates to a separate helper class and forget to implement ITemplateProvider, or when the helper class is static, because a static class can't implement an interface.

In the following example, the LogEntry template is declared in the static class LoggingTemplates.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0274.Error;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        LoggingTemplates.LogEntry();
11
12        return meta.Proceed();
13    }
14}
15
16[RunTimeOrCompileTime]
17internal static class LoggingTemplates
18{
19    // Error: LoggingTemplates is not an aspect, a fabric, or an ITemplateProvider.
20    [Template]
    Error LAMA0274: The template 'LoggingTemplates.LogEntry()' is contained in 'LoggingTemplates', which is not an aspect, a fabric, or a type implementing ITemplateProvider.

21    public static void LogEntry()
22    {
23        Console.WriteLine( $"Entering {meta.Target.Method}." );
24    }
25}
26
1namespace Doc.LAMA0274.Error;
2
3internal class Calculator
4{
5    [Log]
6    public int Add( int a, int b ) => a + b;
7}
8

Resolution

Do one of the following:

  • Make the containing type implement ITemplateProvider. If the type is a static class, remove the static modifier and add a private constructor to prevent instantiation. The templates themselves can remain static.
  • Move the template to the aspect or fabric that uses it.

In the following example, LoggingTemplates implements ITemplateProvider.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0274.Fixed;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        LoggingTemplates.LogEntry();
11
12        return meta.Proceed();
13    }
14}
15
16// Fixed: the class implements ITemplateProvider. It can't be static, so it has a private constructor instead.
17internal class LoggingTemplates : ITemplateProvider
18{
19    private LoggingTemplates() { }
20
21    [Template]
22    public static void LogEntry()
23    {
24        Console.WriteLine( $"Entering {meta.Target.Method}." );
25    }
26}
27
Source Code
1namespace Doc.LAMA0274.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.LAMA0274.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