Open sandboxFocusImprove this doc

LAMA0210: Metalama can't generate a serializer for a positional record

Severity Error
Reported by Metalama.Framework
Message Cannot generate a compile-time serializer for '<Type>' because generated serializers are not currently supported for a positional record class or struct. You can provide a manual serializer (public nested class) derived from ReferenceTypeSerializer (record classes) or ValueTypeSerializer (record structs) instead.

Cause

Metalama serializes aspects, fabrics, and other types implementing ICompileTimeSerializable when they have cross-project effects. By default, it generates a serializer for each of these types, unless the type declares its own nested serializer.

Metalama can't generate a serializer for a positional record, that is, a record, record class, or record struct declared with a parameter list. Metalama reports LAMA0210 when a positional record implements ICompileTimeSerializable, directly or through a base type, and doesn't declare a manual serializer. In the message, <Type> is the record.

In the following example, the RetryPolicy positional record implements ICompileTimeSerializable so that the Retry aspect can store it in a property.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0210.Error;
5
6public class RetryAttribute : OverrideMethodAspect
7{
8    public RetryAttribute( int maxAttempts )
9    {
10        this.Policy = new RetryPolicy( maxAttempts );
11    }
12
13    public RetryPolicy Policy { get; }
14
15    public override dynamic? OverrideMethod()
16    {
17        for ( var attempt = 1;; attempt++ )
18        {
19            try
20            {
21                return meta.Proceed();
22            }
23            catch ( Exception ) when ( attempt < this.Policy.MaxAttempts )
24            {
25                Console.WriteLine( $"Attempt {attempt} failed. Retrying." );
26            }
27        }
28    }
29}
30
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0210.Error;
6
7// Metalama cannot generate a serializer for a positional record.
8[RunTimeOrCompileTime]
Error LAMA0210: Cannot generate a compile-time serializer for 'RetryPolicy' because generated serializers are not currently supported for a positional record class or struct. You can provide a manual serializer (public nested class) derived from ReferenceTypeSerializer (record classes) or ValueTypeSerializer (record structs) instead.

9public record RetryPolicy( int MaxAttempts ) : ICompileTimeSerializable;
10
11public class OrderService
12{
13    [Retry( 3 )]
14    public void PlaceOrder( int orderId )
15    {
16        Console.WriteLine( $"Placing order {orderId}." );
17    }
18}
19

Resolution

Do one of the following:

  • Add a nested serializer class to the record: derive it from ReferenceTypeSerializer<T> for a record class or from ValueTypeSerializer<T> for a record struct. The following example shows this fix.
  • Declare the record without a parameter list, with ordinary properties instead of positional parameters. Metalama can generate serializers for such records.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0210.Fixed;
5
6public class RetryAttribute : OverrideMethodAspect
7{
8    public RetryAttribute( int maxAttempts )
9    {
10        this.Policy = new RetryPolicy( maxAttempts );
11    }
12
13    public RetryPolicy Policy { get; }
14
15    public override dynamic? OverrideMethod()
16    {
17        for ( var attempt = 1;; attempt++ )
18        {
19            try
20            {
21                return meta.Proceed();
22            }
23            catch ( Exception ) when ( attempt < this.Policy.MaxAttempts )
24            {
25                Console.WriteLine( $"Attempt {attempt} failed. Retrying." );
26            }
27        }
28    }
29}
30
Source Code
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0210.Fixed;
6
7[RunTimeOrCompileTime]
8public record RetryPolicy( int MaxAttempts ) : ICompileTimeSerializable
9{
10    // The record now provides its own serializer.
11    public class Serializer : ReferenceTypeSerializer<RetryPolicy>
12    {




13        public override RetryPolicy CreateInstance( IArgumentsReader constructorArguments )
14            => new( constructorArguments.GetValue<int>( "MaxAttempts" ) );
15
16        public override void SerializeObject( RetryPolicy obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
17            => constructorArguments.SetValue( "MaxAttempts", obj.MaxAttempts );
18    }
19}
20




21public class OrderService
22{
23    [Retry( 3 )]
24    public void PlaceOrder( int orderId )







25    {
26        Console.WriteLine( $"Placing order {orderId}." );
27    }


28}


29
Transformed Code
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0210.Fixed;
6
7[RunTimeOrCompileTime]
8public record RetryPolicy(int MaxAttempts) : ICompileTimeSerializable
9{
10    // The record now provides its own serializer.
11
12#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
13
14
15    public class Serializer : ReferenceTypeSerializer<RetryPolicy>
16    {
17        public override RetryPolicy CreateInstance(IArgumentsReader constructorArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
18
19
20        public override void SerializeObject(RetryPolicy obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
21    }
22

23#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
24
25
26}
27
28public class OrderService
29{
30    [Retry(3)]
31    public void PlaceOrder(int orderId)
32    {
33        for (var attempt = 1; ; attempt++)
34        {
35            try
36            {
37                Console.WriteLine($"Placing order {orderId}.");
38                return;
39            }
40            catch (Exception) when (attempt < 3)
41            {
42                Console.WriteLine($"Attempt {attempt} failed. Retrying.");
43            }
44        }
45    }
46}
47

See also