| Severity | Error |
| Reported by | Metalama.Framework |
| Message | Accessing the static interface member '<Member>' is not supported on the compile-time template type parameter '<TypeParameter>'. Call a run-time generic method that accesses the member instead, or make the type parameter run-time. |
Cause
A template method can have compile-time type parameters, marked with the [CompileTime] attribute. When Metalama expands the template, it replaces each compile-time type parameter with the type passed by the aspect, for instance int.
When a type parameter is constrained to an interface with static abstract members, like INumber, C# lets you access these members through the type parameter, for instance T.Zero. Metalama doesn't support this syntax when T is a compile-time template type parameter, and reports LAMA0265. In the message, <Member> is the name of the member and <TypeParameter> is the type parameter.
In the following example, the PrintZero template accesses T.Zero, where T is a compile-time type parameter.
1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5using System.Numerics;
6
7namespace Doc.LAMA0265.Error;
8
9public class AddPrintZeroAttribute : TypeAspect
10{
11 public override void BuildAspect( IAspectBuilder<INamedType> builder )
12 {
13 builder.IntroduceMethod( nameof(this.PrintZero), args: new { T = typeof(int) } );
14 }
15
16 [Template]
17 public void PrintZero<[CompileTime] T>()
18 where T : INumber<T>
19 {
20 // Error: T is a compile-time type parameter, so its static interface members cannot be accessed.
Error LAMA0265: Accessing the static interface member 'Zero' is not supported on the compile-time template type parameter 'T'. Call a run-time generic method that accesses the member instead, or make the type parameter run-time.
21 Console.WriteLine( T.Zero );
22 }
23}
24
1namespace Doc.LAMA0265.Error;
2
3[AddPrintZero]
4internal partial class Calculator
5{
6 public int Add( int a, int b ) => a + b;
7}
8
Resolution
Do one of the following:
- Move the access to a run-time generic helper method, and call this method from the template with
Tas the type argument. The generated code calls the helper with the actual type. - Remove the [CompileTime] attribute from the type parameter. The introduced method then becomes a generic method, and the static member is accessed at run time.
In the following example, the template calls a NumberHelper.Zero<T> helper method.
1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5using System.Numerics;
6
7namespace Doc.LAMA0265.Fixed;
8
9public class AddPrintZeroAttribute : TypeAspect
10{
11 public override void BuildAspect( IAspectBuilder<INamedType> builder )
12 {
13 builder.IntroduceMethod( nameof(this.PrintZero), args: new { T = typeof(int) } );
14 }
15
16 [Template]
17 public void PrintZero<[CompileTime] T>()
18 where T : INumber<T>
19 {
20 // Fixed: the static interface member is accessed by a run-time generic helper method.
21 Console.WriteLine( NumberHelper.Zero<T>() );
22 }
23}
24
25public static class NumberHelper
26{
27 public static T Zero<T>()
28 where T : INumber<T>
29 => T.Zero;
30}
31
1namespace Doc.LAMA0265.Fixed;
2
3[AddPrintZero]
4internal partial class Calculator
5{
6 public int Add( int a, int b ) => a + b;
7}
8
1using System;
2
3namespace Doc.LAMA0265.Fixed;
4
5[AddPrintZero]
6internal partial class Calculator
7{
8 public int Add(int a, int b) => a + b;
9
10 public void PrintZero()
11 {
12 Console.WriteLine(NumberHelper.Zero<int>());
13 }
14}
15