| Severity | Error |
| Reported by | Metalama.Framework |
| Message | Cannot generate a compile-time serializer for '<Type>' because the serializer '<BaseTypeSerializer>' of its base type does not have a public or protected parameterless constructor. Add such a constructor to '<BaseTypeSerializer>'. |
Cause
When Metalama builds the compile-time code of a project, it generates a serializer for every type that implements ICompileTimeSerializable and doesn't have a manual serializer. When the base type has a manual serializer, that is, a nested class derived from ReferenceTypeSerializer, the generated serializer derives from it, and its constructor calls the parameterless constructor of this base serializer.
Metalama reports LAMA0207 when the base type of the serializable type <Type> has a manual serializer <BaseTypeSerializer> that has no public or protected parameterless constructor. A serializer whose only parameterless constructor is private or internal is rejected too, because the generated serializer couldn't call it.
In the following example, the manual serializer of LogCategory has a single constructor, which takes the key under which the name is stored. Metalama can't generate the serializer of the derived class DatabaseLogCategory.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0207.Error;
6
7[RunTimeOrCompileTime]
8public class LogCategory : ICompileTimeSerializable
9{
10 public string Name { get; set; } = "Default";
11
12 public class Serializer : ReferenceTypeSerializer
13 {
14 private readonly string _key;
15
16 // The only constructor of the serializer has a parameter.
17 public Serializer( string key )
18 {
19 this._key = key;
20 }
21
22 public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new LogCategory();
23
24 public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
25 => initializationArguments.SetValue( this._key, ((LogCategory) obj).Name );
26
27 public override void DeserializeFields( object obj, IArgumentsReader initializationArguments )
28 => ((LogCategory) obj).Name = initializationArguments.GetValue<string>( this._key ) ?? "Default";
29 }
30}
31
32// Error: the base serializer LogCategory.Serializer has no parameterless constructor.
33[RunTimeOrCompileTime]
Error LAMA0207: Cannot generate a compile-time serializer for 'DatabaseLogCategory' because the serializer 'LogCategory.Serializer' of its base type does not have a public or protected parameterless constructor. Add such a constructor to 'LogCategory.Serializer'.
34public class DatabaseLogCategory : LogCategory
35{
36 public int Level { get; set; }
37
38 public DatabaseLogCategory()
39 {
40 this.Name = "Database";
41 }
42}
43
Resolution
Add a public or protected parameterless constructor to the manual serializer of the base type. You can keep the other constructors.
In the following example, the serializer has a parameterless constructor that calls the other constructor with a default key.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0207.Fixed;
6
7[RunTimeOrCompileTime]
8public class LogCategory : ICompileTimeSerializable
9{
10 public string Name { get; set; } = "Default";
11
12 public class Serializer : ReferenceTypeSerializer
13 {
14 private readonly string _key;
15
16 public Serializer( string key )
17 {
18 this._key = key;
19 }
20
21 // Fixed: a parameterless constructor that derived serializers can call.
22 public Serializer() : this( "Name" ) { }
23 public override object CreateInstance( Type type, IArgumentsReader constructorArguments ) => new LogCategory();
24
25 public override void SerializeObject( object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments )
26 => initializationArguments.SetValue( this._key, ((LogCategory) obj).Name );
27
28 public override void DeserializeFields( object obj, IArgumentsReader initializationArguments )
29 => ((LogCategory) obj).Name = initializationArguments.GetValue<string>( this._key ) ?? "Default";
30 }
31}
32
33[RunTimeOrCompileTime]
34public class DatabaseLogCategory : LogCategory
35{
36 public int Level { get; set; }
37
38 public DatabaseLogCategory()
39 {
40 this.Name = "Database";
41 }
42}
43
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Serialization;
3using System;
4
5namespace Doc.LAMA0207.Fixed;
6
7
8#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
9
10[RunTimeOrCompileTime]
11public class LogCategory : ICompileTimeSerializable
12{
13 public string Name { get; set; } = "Default";
14
15
16#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
17
18 public class Serializer : ReferenceTypeSerializer
19 {
20 private readonly string _key;
21
22 public Serializer(string key)
23 {
24 this._key = key;
25 }
26
27 // Fixed: a parameterless constructor that derived serializers can call.
28 public Serializer() : this("Name") { }
29 public override object CreateInstance(Type type, IArgumentsReader constructorArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
30
31
32 public override void SerializeObject(object obj, IArgumentsWriter constructorArguments, IArgumentsWriter initializationArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
33
34
35 public override void DeserializeFields(object obj, IArgumentsReader initializationArguments) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
36 }
37
38#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
39
40
41}
42
43#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
44
45
46
47[RunTimeOrCompileTime]
48public class DatabaseLogCategory : LogCategory
49{
50 public int Level { get; set; }
51
52 public DatabaseLogCategory()
53 {
54 this.Name = "Database";
55 }
56}
57