| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The class '<ClassName>' defines a new template named '<TemplateName>', but the base class '<BaseClassName>' already defines a template of the same name. Rename the template, or make the template of the base class virtual and override it. |
Cause
Advice methods such as Override or IntroduceMethod identify templates by their name. Therefore, all templates of an aspect class, including the templates inherited from its base classes, must have different names.
Metalama reports LAMA0036 when a class derived from an aspect class defines a template that has the same name as a template of a base class, but doesn't override it. This happens, for instance, when the derived class hides the base template with the new modifier. In the message, <TemplateName> is the template name, <ClassName> is the derived class, and <BaseClassName> is its base class.
Metalama reports this error when it loads the aspect class, whether or not the aspect is used.
In the following example, the TimedLog aspect derives from the Log aspect and hides its LogTemplate template with a new one.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0036.Error;
6
7public class LogAttribute : MethodAspect
8{
9 public override void BuildAspect( IAspectBuilder<IMethod> builder )
10 {
11 builder.Override( nameof(this.LogTemplate) );
12 }
13
14 [Template]
15 public dynamic? LogTemplate()
16 {
17 Console.WriteLine( $"Executing {meta.Target.Method}." );
18
19 return meta.Proceed();
20 }
21}
22
23public class TimedLogAttribute : LogAttribute
24{
25 // Error: the base class already defines a template named LogTemplate.
26 [Template]
Error LAMA0036: The class 'TimedLogAttribute' defines a new template named 'LogTemplate', but the base class 'LogAttribute' already defines a template of the same name. Rename the template, or make the template of the base class virtual and override it.
27 public new dynamic? LogTemplate()
28 {
29 Console.WriteLine( $"{DateTime.Now:T} Executing {meta.Target.Method}." );
30
31 return meta.Proceed();
32 }
33}
34
1namespace Doc.LAMA0036.Error;
2
3internal class Calculator
4{
5 [TimedLog]
6 public int Add( int a, int b ) => a + b;
7}
8
Resolution
Do one of the following:
- If the derived class should change the behavior of the base template, make the base template
virtualand override it in the derived class. Don't add the [Template] attribute to the override: it inherits the attribute of the base method. The following example shows this fix. - If both templates are needed, rename the template of the derived class.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0036.Fixed;
6
7public class LogAttribute : MethodAspect
8{
9 public override void BuildAspect( IAspectBuilder<IMethod> builder )
10 {
11 builder.Override( nameof(this.LogTemplate) );
12 }
13
14 [Template]
15 public virtual dynamic? LogTemplate()
16 {
17 Console.WriteLine( $"Executing {meta.Target.Method}." );
18
19 return meta.Proceed();
20 }
21}
22
23public class TimedLogAttribute : LogAttribute
24{
25 // Fixed: the template overrides the virtual template of the base class.
26 public override dynamic? LogTemplate()
27 {
28 Console.WriteLine( $"{DateTime.Now:T} Executing {meta.Target.Method}." );
29
30 return meta.Proceed();
31 }
32}
33
1namespace Doc.LAMA0036.Fixed;
2
3internal class Calculator
4{
5 [TimedLog]
6 public int Add( int a, int b ) => a + b;
7}
8
1using System;
2
3namespace Doc.LAMA0036.Fixed;
4
5internal class Calculator
6{
7 [TimedLog]
8 public int Add(int a, int b)
9 {
10 Console.WriteLine($"{(DateTime.Now):T} Executing Calculator.Add(int, int).");
11 return a + b;
12 }
13}
14