繁体   English   中英

无法在 C# 中序列化字典

[英]Cannot serialize Dictionary in C#

我将请求模型作为参数传递给我的 API 以用于 POST 请求,并且请求模型上的属性之一是 Dictionary<int, OrderFood> 类型。 我正在使用 Swagger 来测试操作方法,我得到的错误响应是:

“不支持集合类型 'System.Collections.Generic.Dictionary`2[System.int32, OrderFood]。'”

我知道目前不支持序列化非字符串键字典,我需要实现自定义 JSON 转换器。 这是请求模型类:

    [JsonConverter(typeof(JsonNonStringKeyDictionaryConverter<int, OrderFood>))]
public class FoodOrderRequestModel
{
    public string ModelName { get; set; }

    public string DisplayName { get; set; }

    public string Type { get; set; }

    public object ModelValue { get; set; }

    public object DisplayValue { get; set; }

    public Dictionary<int, OrderFood> Items { get; set; }
}

这是转换器:

internal sealed class JsonNonStringKeyDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
{
    public override IDictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var convertedType = typeof(Dictionary<,>)
            .MakeGenericType(typeof(string), typeToConvert.GenericTypeArguments[1]);
        var value = JsonSerializer.Deserialize(ref reader, convertedType, options);
        var instance = (Dictionary<TKey, TValue>)Activator.CreateInstance(
            typeToConvert,
            BindingFlags.Instance | BindingFlags.Public,
            null,
            null,
            CultureInfo.CurrentCulture);
        var enumerator = (IEnumerator)convertedType.GetMethod("GetEnumerator")!.Invoke(value, null);
        var parse = typeof(TKey).GetMethod("Parse", 0, BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Any, new[] { typeof(string) }, null);
        if (parse == null)
        {
            throw new NotSupportedException($"{typeof(TKey)} as TKey in IDictionary<TKey, TValue> is not supported.");
        }

        while (enumerator.MoveNext())
        {
            var element = (KeyValuePair<string?, TValue>)enumerator.Current;
            instance.Add((TKey)parse.Invoke(null, new[] { element.Key }), element.Value);
        }

        return instance;
    }

    public override void Write(Utf8JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializerOptions options)
    {
        var convertedDictionary = new Dictionary<string?, TValue>(value.Count);
        foreach (var (k, v) in value)
        {
            convertedDictionary[k?.ToString()] = v;
        }

        JsonSerializer.Serialize(writer, convertedDictionary, options);
        convertedDictionary.Clear();
    }
}

internal sealed class JsonNonStringKeyDictionaryConverterFactory : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        if (!typeToConvert.IsGenericType)
        {
            return false;
        }

        if (typeToConvert.GenericTypeArguments[0] == typeof(string))
        {
            return false;
        }

        return typeToConvert.GetInterface("IDictionary") != null;
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        var converterType = typeof(JsonNonStringKeyDictionaryConverter<,>)
            .MakeGenericType(typeToConvert.GenericTypeArguments[0], typeToConvert.GenericTypeArguments[1]);
        var converter = (JsonConverter)Activator.CreateInstance(
            converterType,
            BindingFlags.Instance | BindingFlags.Public,
            null,
            null,
            CultureInfo.CurrentCulture);
        return converter;
    }
}

序列化发生在我的 API 上的任何断点之前,所以我不确定如何测试我的转换器以查看它是否已添加到管道中。 我也不确定 JsonNonStringKeyDictionaryConverter<,> 的位置,因为我已经看到它直接位于属性上方的某些实现。 非常感谢任何建议或帮助。

将 System.Text.Json NuGet 包更新/添加到 LTS 版本 5.0.1 适用于 .NET Core 3.1 应用程序。

特别感谢@CoolBots在 github https://github.com/dotnet/runtime/issues/30524#issuecomment-524619972上的主题讨论

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM