Json.NET:反序列化嵌套字典

ffscu2ro  于 2023-02-26  发布在  .NET
关注(0)|答案(7)|浏览(178)

将对象反序列化为DictionaryJsonConvert.DeserializeObject<IDictionary<string,object>>(json))时,嵌套对象会反序列化为JObject。是否可以强制将嵌套对象反序列化为Dictionary

jaxagkaj

jaxagkaj1#

我发现了一种通过提供CustomCreationConverter实现将所有嵌套对象转换为Dictionary<string,object>的方法:

class MyConverter : CustomCreationConverter<IDictionary<string, object>>
{
    public override IDictionary<string, object> Create(Type objectType)
    {
        return new Dictionary<string, object>();
    }

    public override bool CanConvert(Type objectType)
    {
        // in addition to handling IDictionary<string, object>
        // we want to handle the deserialization of dict value
        // which is of type object
        return objectType == typeof(object) || base.CanConvert(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject
            || reader.TokenType == JsonToken.Null)
            return base.ReadJson(reader, objectType, existingValue, serializer);

        // if the next token is not an object
        // then fall back on standard deserializer (strings, numbers etc.)
        return serializer.Deserialize(reader);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var json = File.ReadAllText(@"c:\test.json");
        var obj = JsonConvert.DeserializeObject<IDictionary<string, object>>(
            json, new JsonConverter[] {new MyConverter()});
    }
}

文件:* * 一个

wb1gzix0

wb1gzix02#

当我遇到这个问题时,我有一个非常相似但稍微复杂一些的需求。起初我想也许我可以修改公认的答案,但这似乎有点复杂,我最终采取了一种不同的方法。我试图将一个现代的JSON层放在一个遗留的C++ API之上。我不想给你讲细节,只想说需求归结为:

  • JSON对象变为Dictionary<string,object>
  • JSON数组变为List<object>
  • JSON值成为相应的原始CLR值。
  • 对象和数组可以无限嵌套。

我首先将请求字符串反序列化为一个Newtonsoft JSON对象,然后调用我的方法根据上述要求进行转换:

var jsonObject = JsonConvert.DeserializeObject(requestString);
var apiRequest = ToApiRequest(jsonObject);
// call the legacy C++ API ...

下面是我的方法,它可以转换为API所期望的结构:

private static object ToApiRequest(object requestObject)
    {
        switch (requestObject)
        {
            case JObject jObject: // objects become Dictionary<string,object>
                return ((IEnumerable<KeyValuePair<string, JToken>>) jObject).ToDictionary(j => j.Key, j => ToApiRequest(j.Value));
            case JArray jArray: // arrays become List<object>
                return jArray.Select(ToApiRequest).ToList();
            case JValue jValue: // values just become the value
                return jValue.Value;
            default: // don't know what to do here
                throw new Exception($"Unsupported type: {requestObject.GetType()}");
        }
    }

我希望有人能发现这种方法是有用的。

6qqygrtg

6qqygrtg3#

替代/更新:
我需要反序列化String s的字典的字典,并且使用当前的Json .NET(5.0),我不必创建CustomConverter,我只使用(在VB .NET中):

JsonConvert.DeserializeObject(Of IDictionary(Of String, IDictionary(Of String, String)))(jsonString)

或者,在C#中:

JsonConvert.DeserializeObject<IDictionary<String, IDictionary<String, String>>(jsonString);
dba5bblo

dba5bblo4#

我有一个嵌套/深结构的“未知”字典是序列化/反序列化到/从C#对象和JSON字符串。
如果我使用Newtonsoft,它不会自动工作。
如果我使用System.Text.Json,它会自动工作。

//does NOT work (newtonDeserialized does not have the same data in the nested Dictionaries as in object):
var newtonSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(object);
var newtonDeserialized = Newtonsoft.Json.JsonConvert.DeserializeObject<WaitlistResponse>(newtonSerialized);

//Works (netDeserialized have the same data in the nested Directories as in object):
var netSerialized = System.Text.Json.JsonSerializer.Serialize(object);
var netDeserialized = System.Text.Json.JsonSerializer.Deserialize<WaitlistResponse>(netSerialized);
wpx232ag

wpx232ag5#

@AlexD的公认解决方案在json中有数组的情况下不能理想地工作,它返回JObjectJArray,而不是List<Dictionary<string, object>>
这可以通过修改ReadJson()方法来解决:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.StartObject || reader.TokenType == JsonToken.Null)
        return base.ReadJson(reader, objectType, existingValue, serializer);

    //if it's an array serialize it as a list of dictionaries
    if(reader.TokenType == JsonToken.ArrayStart)
        return serializer.Deserialize(reader, typeof(List<Dictionary<string, object>>));    

    // if the next token is not an object
    // then fall back on standard deserializer (strings, numbers etc.)
    return serializer.Deserialize(reader);
}
cnwbcb6i

cnwbcb6i6#

在我的例子中,并不是所有的东西都是嵌套字典,我还有一个基元类型的key-value数组,当数组的对象不是字典时,它抛出异常。
根据菲利普的回答我得出了

public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue,
            JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.StartObject || reader.TokenType == JsonToken.Null)
                return base.ReadJson(reader, objectType, existingValue, serializer);

            //if it's an array serialize it as a list of dictionaries
            if (reader.TokenType == JsonToken.StartArray)
            {
                return serializer.Deserialize(reader, typeof(List<object>)); // instead of List<Dictionary<string, object>>
            }

            // if the next token is not an object
            // then fall back on standard deserializer (strings, numbers etc.)
            return serializer.Deserialize(reader);
        }

希望对那些还没开始工作的人有帮助。

at0kjp5o

at0kjp5o7#

首先,您需要序列化字典值。

var settings = new JsonSerializerSettings { TypeNameHandling= TypeNameHandling.All };

var serializeValues = JsonConvert.SerializeObject(nestedDictionaryValues, settings);

//After serialize using deserialize using the same TypeNameHandling.

var deserializeValues = JsonConvert.DeserializeObject(serializeValues, settings);

相关问题