-
Notifications
You must be signed in to change notification settings - Fork 6k
Closed
Labels
dotnet/svcneeds-more-infoNeeds more info from OP. Auto-closed after 2 weeks if no response. [org][resolution]Needs more info from OP. Auto-closed after 2 weeks if no response. [org][resolution]
Description
AOT does not like reflection and factories building objects from reflection, as it needs to detect all types used in the app from the static analysis, to be able to strip unused classes and methods, and to precompile used classes and methods to machine code for performance.
The example you provide DictionaryTKeyEnumTValueConverter fall typically in this case.
The way to go is to use the inner class as the converter. So make i made it public, without requiring the json options, as it is unavailable there.
public class DictionaryEnumConverter<TKey, TValue> : JsonConverter<Dictionary<TKey, TValue>> where TKey : struct, Enum
{
private JsonConverter<TValue> _valueConverter;
private bool valueConverterSearched = false;
private Type _valueType = typeof(TValue);
public DictionaryEnumConverter()
{
}
public override Dictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// For performance, use the existing converter if available.
if (!valueConverterSearched)
{
_valueConverter = (JsonConverter<TValue>)options.GetConverter(typeof(TValue));
valueConverterSearched = true;
}
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException();
var dictionary = new Dictionary<TKey, TValue>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
return dictionary;
// Get the key.
if (reader.TokenType != JsonTokenType.PropertyName)
throw new JsonException();
var propertyName = reader.GetString();
// For performance, parse with ignoreCase:false first.
if (!Enum.TryParse(propertyName, ignoreCase: false, out TKey key) &&
!Enum.TryParse(propertyName, ignoreCase: true, out key))
{
throw new JsonException($"Unable to convert \"{propertyName}\" to Enum \"{typeof(TKey)}\".");
}
// Get the value.
TValue v;
if (_valueConverter != null)
{
reader.Read();
v = _valueConverter.Read(ref reader, _valueType, options);
}
else
{
v = JsonSerializer.Deserialize<TValue>(ref reader, options);
}
// Add to dictionary.
dictionary.Add(key, v);
}
throw new JsonException("Missing EndObject on dictionary");
}
public override void Write(Utf8JsonWriter writer, Dictionary<TKey, TValue> dictionary, JsonSerializerOptions options)
{
// For performance, use the existing converter if available.
if (!valueConverterSearched)
{
_valueConverter = (JsonConverter<TValue>)options.GetConverter(typeof(TValue));
valueConverterSearched = true;
}
writer.WriteStartObject();
foreach (var kvp in dictionary)
{
writer.WritePropertyName(kvp.Key.ToString());
if (_valueConverter != null)
_valueConverter.Write(writer, kvp.Value, options);
else
JsonSerializer.Serialize(writer, kvp.Value, options);
}
writer.WriteEndObject();
}
}
Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
- ID: 5de37d79-751f-e372-e866-efde28f4908c
- Version Independent ID: 678c4f23-764a-7ccd-0d6d-159a30957477
- Content: How to write custom converters for JSON serialization - .NET
- Content Source: docs/standard/serialization/system-text-json-converters-how-to.md
- Product: dotnet
- GitHub Login: @tdykstra
- Microsoft Alias: tdykstra
Metadata
Metadata
Assignees
Labels
dotnet/svcneeds-more-infoNeeds more info from OP. Auto-closed after 2 weeks if no response. [org][resolution]Needs more info from OP. Auto-closed after 2 weeks if no response. [org][resolution]