C# 如何将非类型值的多态字典的值反序列化到传统的.Net数组中?

C# 如何将非类型值的多态字典的值反序列化到传统的.Net数组中?,c#,json,json.net,C#,Json,Json.net,我有一个具有属性的类 public Dictionary<string, object> Attributes { get; set; } 公共字典属性{get;set;} 属性值只能是字符串、数字、字符串数组和数字数组 我现在有一个JSON字符串(没有类型信息),并希望将其反序列化为该类的对象。问题是作为数组的属性值被反序列化为JArray对象,而不是string[]或long[] 如何执行反序列化以使属性“Attribute”的结果字典值都是string、long、strin

我有一个具有属性的类

public Dictionary<string, object> Attributes { get; set; }
公共字典属性{get;set;}
属性值只能是字符串、数字、字符串数组和数字数组

我现在有一个JSON字符串(没有类型信息),并希望将其反序列化为该类的对象。问题是作为数组的属性值被反序列化为
JArray
对象,而不是
string[]
long[]


如何执行反序列化以使属性“Attribute”的结果字典值都是
string
long
string[]
long[]
(或者包含字符串和long的
对象[]
)?

一种解决方案是创建一个for
字典,该字典将逻辑从调整到,以返回所需的特定类型的数组,而不仅仅是
列表
集合

首先,定义以下转换器和扩展方法:

public class ObjectDictionaryConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Dictionary<string, object>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var tokenType = reader.SkipComments().TokenType;
        if (tokenType == JsonToken.Null)
            return null;

        var tempDictionary = new Dictionary<string, object>();
        var old = reader.DateParseHandling;
        try
        {
            // Disable recognition of date strings
            reader.DateParseHandling = DateParseHandling.None;
            serializer.Populate(reader, tempDictionary);
        }
        finally
        {
            reader.DateParseHandling = old;
        }

        var dictionary = existingValue as IDictionary<string, object> ?? (IDictionary<string, object>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
        foreach (var pair in tempDictionary)
            dictionary.Add(pair.Key, pair.Value.ToObject());

        return dictionary;
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

public static partial class JsonExtensions
{
    public static JsonReader SkipComments(this JsonReader reader)
    {
        while (reader.TokenType == JsonToken.Comment && reader.Read())
            ;
        return reader;
    }

    public static object ToObject(this object obj)
    {
        return ToObject(obj as JToken) ?? obj;
    }

    public static object ToObject(this JToken token)
    {
        // Adapts the logic from https://stackoverflow.com/a/19140420/3744182) 
        // to https://stackoverflow.com/q/5546142/3744182
        // By [Brian Rogers](https://stackoverflow.com/users/10263/brian-rogers)

        if (token == null)
            return null;

        switch (token.Type)
        {
            case JTokenType.Null:
                return null;

            case JTokenType.Object:
                return token.Children<JProperty>()
                            .ToDictionary(prop => prop.Name,
                                          prop => ToObject(prop.Value));

            case JTokenType.Array:
                {
                    var list = token.Select(t => ToObject(t)).ToList();
                    if (list.All(i => i is long))
                        return list.Cast<long>().ToArray();
                    else if (list.All(i => i is string))
                        return list.Cast<string>().ToArray();
                    else return list.ToArray();
                }

            default:
                return ((JValue)token).Value;
        }
    }
}
注:

  • 因为您知道字典值应该是字符串而不是
    DateTime
    值,所以我禁用了Json.NET的自动日期识别。有关日期识别的详细信息,请参阅
演示小提琴。

相关:。也相关:。
var settings = new JsonSerializerSettings
{
    Converters = { new ObjectDictionaryConverter() },
};
var deserializedObj = JsonConvert.DeserializeObject<AttributeObject>(jsonString, settings);