| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The template property '<Property>' cannot be abstract because its type or the type of one of its parameters is run-time-only. Make the template property virtual and give it a default implementation. |
Cause
When Metalama builds the compile-time assembly of your project, it compiles every template into compile-time code and removes the template's original declaration. An abstract template has no body to compile, so Metalama keeps its declaration as is in the compile-time assembly. This is possible only if every type in the declaration can be used at compile time. Types defined in your project are run-time-only unless you mark them otherwise, and the compile-time assembly can't reference them.
Metalama reports LAMA0237 when an aspect declares an abstract template property, for instance an abstract property with the IntroduceAttribute or TemplateAttribute attribute, and the property type or one of the indexer parameter types is run-time-only. This typically happens in a base aspect that expects derived aspects to provide the implementation of an introduced property. Metalama then stops building the compile-time assembly, so a derived aspect that overrides the property doesn't cause additional errors.
In the following example, the abstract Clock aspect expects derived aspects to implement the introduced Clock property, but the property type, IClock, is a run-time-only interface defined in the project.
1using Metalama.Framework.Aspects;
2
3namespace Doc.LAMA0237.Error;
4
5public abstract class ClockAttribute : TypeAspect
6{
7 // Error: an abstract template cannot have the run-time-only type IClock.
8 [Introduce]
Error LAMA0237: The template property 'ClockAttribute.Clock' cannot be abstract because its type or the type of one of its parameters is run-time-only. Make the template property virtual and give it a default implementation.
9 public abstract IClock Clock { get; }
10}
11
1using System;
2
3namespace Doc.LAMA0237.Error;
4
5public interface IClock
6{
7 DateTime Now { get; }
8}
9
10public class SystemClock : IClock
11{
12 public DateTime Now => DateTime.Now;
13}
14
15// The abstract ClockAttribute aspect can't be applied until a derived aspect implements the Clock property.
16internal class Invoice { }
17
Resolution
Depending on your intent, do one of the following:
- Make the template property
virtualinstead ofabstractand give it a default implementation. Derived aspects can still override it. The following example uses this fix. - If the type can be used at compile time, mark it with the RunTimeOrCompileTimeAttribute attribute. The type is then also included in the compile-time assembly.
- Change the property type to a type that can be used at compile time, for instance a .NET type.
1using Metalama.Framework.Aspects;
2
3namespace Doc.LAMA0237.Fixed;
4
5public class ClockAttribute : TypeAspect
6{
7 // Fixed: the template is virtual and has a default implementation, which derived aspects can override.
8 [Introduce]
9 public virtual IClock Clock => new SystemClock();
10}
11
1using System;
2
3namespace Doc.LAMA0237.Fixed;
4
5public interface IClock
6{
7 DateTime Now { get; }
8}
9
10public class SystemClock : IClock
11{
12 public DateTime Now => DateTime.Now;
13}
14
15[Clock]
16internal partial class Invoice { }
17
1using System;
2
3namespace Doc.LAMA0237.Fixed;
4
5public interface IClock
6{
7 DateTime Now { get; }
8}
9
10public class SystemClock : IClock
11{
12 public DateTime Now => DateTime.Now;
13}
14
15[Clock]
16internal partial class Invoice
17{
18 public virtual IClock Clock
19 {
20 get
21 {
22 return new SystemClock();
23 }
24 }
25}
26