当前位置: 首页 > 面试题库 >

Newtonsoft Json Deserialize Dictionary作为DataContractJsonSerializer的键/值列表

姚棋
2023-03-14
问题内容

我有一个序列化到DataContractJsonSerializer的字典,我想与Newtonsoft.Json反序列化。

DataContractJsonSerializer已将Dictionary序列化为键/值对的列表:

{"Dict":[{"Key":"Key1","Value":"Val1"},{"Key":"Key2","Value":"Val2"}]}

我可以提供任何很酷的选择JsonConvert.DeserializeObject<>(),使其同时支持该数据格式和Newtonsoft.Json的格式吗?

{"Dict":{"Key1":"Val1","Key2":"Val2"}}

是Newtonsoft.Json创建的漂亮格式,我希望能够在过渡期内读取旧的DataContract格式和新的Newtonsoft格式。

简化示例:

    //[JsonArray]
    public sealed class Data
    {
        public IDictionary<string, string> Dict { get; set; }
    }

    [TestMethod]
    public void TestSerializeDataContractDeserializeNewtonsoftDictionary()
    {
        var d = new Data
        {
            Dict = new Dictionary<string, string>
            {
                {"Key1", "Val1"},
                {"Key2", "Val2"},
            }
        };

        var oldJson = String.Empty;
        var formatter = new DataContractJsonSerializer(typeof (Data));
        using (var stream = new MemoryStream())
        {
            formatter.WriteObject(stream, d);
            oldJson = Encoding.UTF8.GetString(stream.ToArray());
        }

        var newJson = JsonConvert.SerializeObject(d);
        // [JsonArray] on Data class gives:
        //
        // System.InvalidCastException: Unable to cast object of type 'Data' to type 'System.Collections.IEnumerable'.

        Console.WriteLine(oldJson);
        // This is tha data I have in storage and want to deserialize with Newtonsoft.Json, an array of key/value pairs
        // {"Dict":[{"Key":"Key1","Value":"Val1"},{"Key":"Key2","Value":"Val2"}]}

        Console.WriteLine(newJson);
        // This is what Newtonsoft.Json generates and should also be supported:
        // {"Dict":{"Key1":"Val1","Key2":"Val2"}}

        var d2 = JsonConvert.DeserializeObject<Data>(newJson);
        Assert.AreEqual("Val1", d2.Dict["Key1"]);
        Assert.AreEqual("Val2", d2.Dict["Key2"]);

        var d3 = JsonConvert.DeserializeObject<Data>(oldJson);
        // Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into 
        // type 'System.Collections.Generic.IDictionary`2[System.String,System.String]' because the type requires a JSON 
        // object (e.g. {"name":"value"}) to deserialize correctly.
        //
        // To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type
        // to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be 
        // deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from
        // a JSON array.
        //
        // Path 'Dict', line 1, position 9.

        Assert.AreEqual("Val1", d3.Dict["Key1"]);
        Assert.AreEqual("Val2", d3.Dict["Key2"]);
    }

问题答案:

您可以为此使用自定义转换器,具体取决于字典以什么令牌开头,将其反序列化为JSON.NET的默认方式,或将其反序列化为数组,然后将该数组转换为Dictionary

public class DictionaryConverter : JsonConverter
{
    public override object ReadJson(
        JsonReader reader,
        Type objectType,
        object existingValue,
        JsonSerializer serializer)
    {
        IDictionary<string, string> result;

        if (reader.TokenType == JsonToken.StartArray)
        {
            JArray legacyArray = (JArray)JArray.ReadFrom(reader);

            result = legacyArray.ToDictionary(
                el => el["Key"].ToString(),
                el => el["Value"].ToString());
        }
        else 
        {
            result = 
                (IDictionary<string, string>)
                    serializer.Deserialize(reader, typeof(IDictionary<string, string>));
        }

        return result;
    }

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

    public override bool CanConvert(Type objectType)
    {
        return typeof(IDictionary<string, string>).IsAssignableFrom(objectType);
    }

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

然后,您可以使用Dict属性装饰Data类中的JsonConverter属性:

public sealed class Data
{
    [JsonConverter(typeof(DictionaryConverter))]
    public IDictionary<string, string> Dict { get; set; }
}

然后对两个字符串进行反序列化应能按预期工作。



 类似资料:
  • 问题内容: 我想将 每个地图条目转换为-列表中的1个条目作为“键-值” 我搜索了,只发现将值仅映射到List。 我希望将此映射到列表为 等等。 如果我使用foreach,可以很容易地做到这一点,但是我想知道通过流获取它是否可行 问题答案:

  • 问题内容: 我有以下JSON片段: 全部在一个行版本中(适用于字符串文字): 在上述例子中,,,和被需要的,但是和是可选的。 这是我要反序列化的课程: 这是我用来反序列化的代码: 除此以外,一切都进行得相当顺利,并且第一次通过时都是空的。我曾尝试一切在阳光下,试图让他们填充:自定义类,,,无论是后者,和所有其他的集合,似乎适用的。[编辑:我忘记尝试了,这似乎是显而易见的候选人。没用。] 这个问题,

  • 问题内容: 对于我的程序,我想从属性文件中读取一个键,并从该键关联的值列表中读取。 最近我在尝试那样 我的属性文件如下所示- 我想要键A应该有一个包含contains 和B包含的列表。 因此Map应该是这样,但是我 在网上搜索了这种方法,但一无所获。我希望有办法。有什么帮助吗? 问题答案: 尝试将属性编写为以逗号分隔的列表,然后在加载属性文件后拆分值。例如 如果您在值中使用逗号,则还可以使用org

  • 问题 > 我想要一个键值对列表,比如HashMap,或者其他推荐的。 此列表应包含用于检索值的唯一键对象。 键不应该是字符串,因为字符串不是唯一的,可以传递任何值。 常量也是有限的,也使用字符串的概念,不应该被考虑。 示例 > 在这个阶段,我创建了一个包含所有键的枚举。例如,枚举颜色{RED,BLUE},然后将其添加到新的HashMap中。 因此,检索颜色的唯一方法是将枚举用作键列表[color.

  • 问题内容: 我正在尝试对格式的数据调用pyspark的reduceByKey函数 似乎pyspark不会接受数组作为普通键中的键,通过简单地应用.reduceByKey(add)可以减少值。 我已经尝试过先将数组转换为字符串,但是这样做不起作用,因为将字符串后处理回数组的速度太慢。 有没有办法让pyspark将数组用作键或使用另一个函数将字符串快速转换回数组? 这是相关的错误代码 摘要 : 输入:

  • 我有一句名言: 我想把它转换成熊猫数据帧,这样一列是键,另一列是值。我该怎么做? < code>pd。data frame . from _ dict(data)不起作用