| Severity | Error |
| Reported by | Metalama.Framework |
| Message | Cannot serialize the compile-time dictionary to a run-time value because it has an unsupported equality comparer '<Comparer>'. Only the default comparer and, for string keys, the predefined StringComparer comparers such as StringComparer.OrdinalIgnoreCase are supported. |
Cause
When a template uses a compile-time Dictionary in a run-time context, Metalama generates code that creates a new dictionary with the same items. To make the run-time dictionary behave like the compile-time one, the generated code must also pass the same equality comparer to the constructor of the dictionary. Metalama can only generate this code for the following comparers:
- the default comparer of the key type;
- for
stringkeys, the static instances of StringComparer:Ordinal,OrdinalIgnoreCase,InvariantCulture,InvariantCultureIgnoreCase,CurrentCulture, andCurrentCultureIgnoreCase.
Metalama reports LAMA0203 when it expands the template and the dictionary uses any other comparer, for instance an instance of your own class implementing IEqualityComparer, or a comparer created by StringComparer.Create. The error is reported on the target declaration of the aspect. In the message, <Comparer> is the type of the comparer.
In the following example, the aspect builds a dictionary with a custom case-insensitive comparer.
1using Metalama.Framework.Aspects;
2using System;
3using System.Collections.Generic;
4using System.Linq;
5
6namespace Doc.LAMA0203.Error;
7
8public class PropertyTypesAttribute : TypeAspect
9{
10 // Introduces a method that maps property names to type names, ignoring the case of property names.
11 [Introduce]
12 public Dictionary<string, string> GetPropertyTypes()
13 {
14 // Error: the dictionary uses a custom comparer, so it can't be converted to a run-time value.
15 var propertyTypes = meta.Target.Type.Properties.ToDictionary(
16 p => p.Name,
17 p => p.Type.ToDisplayString(),
18 new IgnoreCaseComparer() );
19
20 return propertyTypes;
21 }
22}
23
24[RunTimeOrCompileTime]
25public class IgnoreCaseComparer : IEqualityComparer<string>
26{
27 public bool Equals( string? x, string? y ) => string.Equals( x, y, StringComparison.OrdinalIgnoreCase );
28
29 public int GetHashCode( string obj ) => StringComparer.OrdinalIgnoreCase.GetHashCode( obj );
30}
31
1namespace Doc.LAMA0203.Error;
2
3[PropertyTypes]
Error LAMA0203: Cannot serialize the compile-time dictionary to a run-time value because it has an unsupported equality comparer 'IgnoreCaseComparer'. Only the default comparer and, for string keys, the predefined StringComparer comparers such as StringComparer.OrdinalIgnoreCase are supported.
4public partial class Customer
5{
6 public string? Name { get; set; }
7
8 public int Age { get; set; }
9}
10
Resolution
Do one of the following:
- Use the default comparer or one of the predefined StringComparer instances. In the following example, the custom comparer is replaced by OrdinalIgnoreCase, which has the same behavior.
- If you need a custom comparer, write the creation of the dictionary in the run-time code of the template, passing your comparer to the constructor, and add the items one by one.
1using Metalama.Framework.Aspects;
2using System;
3using System.Collections.Generic;
4using System.Linq;
5
6namespace Doc.LAMA0203.Fixed;
7
8public class PropertyTypesAttribute : TypeAspect
9{
10 // Introduces a method that maps property names to type names, ignoring the case of property names.
11 [Introduce]
12 public Dictionary<string, string> GetPropertyTypes()
13 {
14 // Fixed: StringComparer.OrdinalIgnoreCase is a predefined comparer that Metalama can convert.
15 var propertyTypes = meta.Target.Type.Properties.ToDictionary(
16 p => p.Name,
17 p => p.Type.ToDisplayString(),
18 StringComparer.OrdinalIgnoreCase );
19
20 return propertyTypes;
21 }
22}
23
1namespace Doc.LAMA0203.Fixed;
2
3[PropertyTypes]
4public partial class Customer
5{
6 public string? Name { get; set; }
7
8 public int Age { get; set; }
9}
10
1using System;
2using System.Collections.Generic;
3
4namespace Doc.LAMA0203.Fixed;
5
6[PropertyTypes]
7public partial class Customer
8{
9 public string? Name { get; set; }
10
11 public int Age { get; set; }
12
13 public Dictionary<string, string> GetPropertyTypes()
14 {
15 return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
16 {
17 {
18 "Name",
19 "string?"
20 },
21 {
22 "Age",
23 "int"
24 }
25 };
26 }
27}
28