| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The compile-time serializable type '<Type>' declares several nested types that implement ISerializer. Only one manual serializer is allowed. |
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. To override the generated serializer, you add a nested class that derives from ReferenceTypeSerializer<T> or ValueTypeSerializer<T>.
Metalama looks for the manual serializer among the nested types of the serializable type: it takes any nested type that implements ISerializer, whatever its name. Metalama reports LAMA0208 when it finds more than one such nested type, because it can't choose between them. In the message, <Type> is the serializable type.
In the following example, the RetryPolicy class declares two nested serializers.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0208.Error;
6
7[RunTimeOrCompileTime]
Error LAMA0208: The compile-time serializable type 'RetryPolicy' declares several nested types that implement ISerializer. Only one manual serializer is allowed.
8public class RetryPolicy : ICompileTimeSerializable
9{
10 public int MaxAttempts { get; set; } = 3;
11
12 public class Serializer : ReferenceTypeSerializer
13 {
14 public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new RetryPolicy();
15
16 public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
17 => initializationArguments.SetValue( "maxAttempts", ((RetryPolicy) obj).MaxAttempts );
18
19 public override void DeserializeFields( object obj, IArgumentsReader initializationArguments )
20 => ((RetryPolicy) obj).MaxAttempts = initializationArguments.GetValue<int>( "maxAttempts" );
21 }
22
23 // Error: a second nested type implements ISerializer, so Metalama can't choose between them.
24 public class LegacySerializer : ReferenceTypeSerializer
25 {
26 public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new RetryPolicy();
27
28 public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
29 => initializationArguments.SetValue( "attempts", ((RetryPolicy) obj).MaxAttempts );
30
31 public override void DeserializeFields( object obj, IArgumentsReader initializationArguments )
32 => ((RetryPolicy) obj).MaxAttempts = initializationArguments.GetValue<int>( "attempts" );
33 }
34}
35
Resolution
Keep a single nested type implementing ISerializer in the serializable type:
- Remove the serializers you don't need.
- If you need another serializer for a different purpose, move it out of the serializable type. A serializer that isn't nested in the serializable type is ignored, unless you register it with ImportSerializerAttribute, which is designed for types you don't own.
In the following example, RetryPolicy keeps a single nested serializer.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0208.Fixed;
6
7[RunTimeOrCompileTime]
8public class RetryPolicy : ICompileTimeSerializable
9{
10 public int MaxAttempts { get; set; } = 3;
11
12 // Fixed: the type has a single nested serializer.
13 public class Serializer : ReferenceTypeSerializer
14 {
15 public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new RetryPolicy();
16
17 public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
18 => initializationArguments.SetValue( "maxAttempts", ((RetryPolicy) obj).MaxAttempts );
19
20 public override void DeserializeFields( object obj, IArgumentsReader initializationArguments )
21 => ((RetryPolicy) obj).MaxAttempts = initializationArguments.GetValue<int>( "maxAttempts" );
22 }
23}
24
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0208.Fixed;
6
7
8#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
9
10[RunTimeOrCompileTime]
11public class RetryPolicy : ICompileTimeSerializable
12{
13 public int MaxAttempts { get; set; } = 3;
14
15 // Fixed: the type has a single nested serializer.
16
17#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
18
19
20 public class Serializer : ReferenceTypeSerializer
21 {
22 public override object CreateInstance(Type type, IArgumentsReader constructorArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
23
24
25 public override void SerializeObject(object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
26
27
28 public override void DeserializeFields(object obj, IArgumentsReader initializationArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
29 }
30
31#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
32
33
34}
35
36#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
37
38
39