Newtonsoft Json Deserialize Dictionary从DataContractJsonSerializer的键/值列表 [英] Newtonsoft Json Deserialize Dictionary as Key/Value list from DataContractJsonSerializer

查看:407
本文介绍了Newtonsoft Json Deserialize Dictionary从DataContractJsonSerializer的键/值列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个序列化为DataContractJsonSerializer存储的字典,我想使用Newtonsoft.Json反序列化。



DataContractJsonSerializer将Dictionary序列化为Key /价值对:

  {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& GT; Dict {get;组;
}

[TestMethod]
public void TestSerializeDataContractDeserializeNewtonsoftDictionary()
{
var d = new Data
{
Dict =新词典< 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]给出:
//
// System.InvalidCastException:无法将类型为Data的对象转换为键入System.Collections.IEnumerable。

Console.WriteLine(oldJson);
//这是我存储的数据,并希望使用Newtonsoft.Json反序列化一个键/值对数组
//Dict:[{Key:Key1 ,Value:Val1},{Key:Key2,Value:Val2}}}

Console.WriteLine(newJson);
//这是Newtonsoft.Json生成的,也应该被支持:
// {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:无法反序列化当前的JSON数组(例如[1,2,3])到
//键入'System.Collections.Generic.IDictionary`2 [System.String ,System.String]',因为该类型需要一个JSON
//对象(例如{name:value})来正确反序列化。
//
//要修复此错误,请将JSON更改为JSON对象(例如{name:value})或将反序列化类型
//更改为数组或者实现例如List< T>的收集接口(例如,ICollection,IList)的类型。这可以是
//从JSON数组中反序列化。 JsonArrayAttribute也可以添加到类型,以强制它从
//一个JSON数组反序列化。
//
//路径'Dict',行1,位置9.

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


解决方案

您可以使用自定义转换器为此,取决于字典开始的标志,反序列化JSON.NET的默认方式,或将其反序列化为数组,然后将该数组转换为字典

  public class DictionaryConverter:JsonConverter 
{
public override object ReadJson(
JsonReader reader,
键入objectType,
object existingValue,
JsonSerializer serializer)
{
IDictionary< string,string>结果;

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> ;));
}

返回结果;
}

public override void WriteJson(
JsonWriter writer,对象值,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; }
}
}

然后,您可以装饰<$ c $在数据中,具有 JsonConverter 属性的类别属性

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

然后反序列化这两个字符串应该按预期工作。


I have a dictionary serialized to storage with DataContractJsonSerializer which I would like to deserialize with Newtonsoft.Json.

The DataContractJsonSerializer has serialized the Dictionary to a list of Key/Value pairs:

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

Is there any cool options I can give the JsonConvert.DeserializeObject<>() that will make it support both that data format and the format from Newtonsoft.Json?

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

Is the pretty format Newtonsoft.Json creates, and I would like to be able to read both the old DataContract format and the new Newtonsoft format in a transition period.

Simplified example:

    //[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"]);
    }

解决方案

You could use a custom converter for this, depending on what token the dictionary starts with, deserialize it JSON.NET's default way, or deserialize it into an array and then turn that array into a 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; } 
    }
}

Then, you can decorate the Dict property in the Data class with a JsonConverter attribute:

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

Then deserializing both strings should work as expected.

这篇关于Newtonsoft Json Deserialize Dictionary从DataContractJsonSerializer的键/值列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆