【问题标题】:Use Json.NET to (de)serialize dictionary in the structure used by DataContractJsonSerializer? [duplicate]使用 Json.NET 对 DataContractJsonSerializer 使用的结构中的字典进行(反)序列化? [复制]
【发布时间】:2014-06-04 16:33:56
【问题描述】:

有没有办法使用 Json.NET 进行(反)序列化但继续使用 DataContractJsonSerializer 的字典序列化约定?

也就是说,有没有办法在这种结构中读写JSON:

{ "MyDict" : [
    { "Key" : "One",
      "Value" : 1 },
    { "Key" : "Two",
      "Value" : 2 }
    ] }

使用这样的类(带有 Json.NET 属性):

public class MyClass
{
    public Dictionary<string, int> MyDict { get; set; }
}

似乎 Json.NET 的 KeyValuePairConverter 可能会有所帮助,但如果是这样,我找不到正确的应用方法。

我尝试将MyDict[JsonProperty(ItemConverterType = typeof(KeyValuePairConverter))] 联系起来,this page 甚至似乎暗示这可能有效,但添加这样的属性会导致在序列化过程中出现ArgumentOutOfRangeException

【问题讨论】:

    标签: c# json serialization json.net


    【解决方案1】:

    你说得对,KeyValuePairConverter 在这里似乎无法正常工作。没有深入研究 Json.Net 源代码,我只能推测原因。作为一种解决方法,您可以自定义 JsonConverter 来轻松完成此翻译:

    class MyDictionaryConverter<T> : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(Dictionary<string, T>));
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JArray array = JArray.Load(reader);
            Dictionary<string, T> dict = new Dictionary<string, T>();
            foreach (JObject obj in array.Children<JObject>())
            {
                string key = obj["Key"].ToString();
                T val = obj["Value"].ToObject<T>();
                dict.Add(key, val);
            }
            return dict;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            Dictionary<string, T> dict = (Dictionary<string, T>)value;
            JArray array = new JArray();
            foreach (KeyValuePair<string, T> kvp in dict)
            {
                JObject obj = new JObject();
                obj.Add("Key", kvp.Key);
                obj.Add("Value", JToken.FromObject(kvp.Value));
                array.Add(obj);
            }
            array.WriteTo(writer);
        }
    }
    

    使用[JsonConverter] 属性将转换器应用于字典:

    public class MyClass
    {
        [JsonConverter(typeof(MyDictionaryConverter<int>))]
        public Dictionary<string, int> MyDict { get; set; }
    }
    

    这是一个简短的演示程序,展示了转换器的运行情况(完整的往返):

    class Program
    {
        static void Main(string[] args)
        {
            MyClass mc = new MyClass { MyDict = new Dictionary<string, int>() };
            mc.MyDict.Add("One", 1);
            mc.MyDict.Add("Two", 2);
    
            string json = JsonConvert.SerializeObject(mc, Formatting.Indented);
            Console.WriteLine(json);
            Console.WriteLine();
    
            MyClass mc2 = JsonConvert.DeserializeObject<MyClass>(json);
            foreach (KeyValuePair<string, int> kvp in mc2.MyDict)
            {
                Console.WriteLine(kvp.Key + " == " + kvp.Value);
            }
        }
    }
    

    以上输出:

    {
      "MyDict": [
        {
          "Key": "One",
          "Value": 1
        },
        {
          "Key": "Two",
          "Value": 2
        }
      ]
    }
    
    One == 1
    Two == 2
    

    【讨论】:

    • 如果 Dictionary 是您尝试序列化/反序列化的内容,而不是将其嵌入 MyClass 中怎么办?
    • @Justin - 您可以将转换器的实例传递给(De)SerializeObject,而不是使用属性。但是,请参阅 Json.Net - Serialize Dictionary as Array (of Key Value Pairs) 了解其他解决方案。使用合约解析器可能是更好的解决方案。
    • 在我的例子中,json 有一个“未命名”键值对的对象 {},而不是 []。你能建议在这种情况下该怎么做吗?
    • @shanti 我建议你ask a new question。我不知道“未命名的键值对”是什么意思。您需要在一个问题中说明这一点,并描述您尝试做的与这个问题不同的事情。评论不是一个好地方,因为它们的长度和格式有限。创建新问题时,您可以提供a link back to this one 以提供上下文。
    • 好的,我会这样做的。谢谢你告诉我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多