2017-09-25 264 views
0

我想序列化/反序列化字典,问题是我用StringComparer.OrdinalIgnoreCase比较器创建字典。用StringComparer反序列化JSON字典

这是我遇到的问题的代码片段:

var dict = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 

dict["x"] = new Dictionary<string, string>(); 
dict["x"]["y"] = "something"; 

var serialized = JsonConvert.SerializeObject(dict); 

var unSerialized = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(serialized); 

Console.WriteLine((dict.Comparer == unSerialized.Comparer ? "Same" : "Different")); 

.NET Fiddle - Try It

打印出控制台上执行以下操作:

Different

显然, JSON序列化程序不会序列化我在创建字典时设置的比较器,但问题是我无法设置自Dictionary<TKey, TValue>.Comparer以来事件后的比较器是只读的。

我确定它与一些自定义JsonSerializerSetting有关,但我似乎无法弄清楚如何拦截集合创建并返回一个带有不同比较器的字典。

+0

OK ,罗恩,假设你把这个json发送到另一个站点。它如何知道你是如何构建这个词典的(你甚至可以使用其他方法而不需要任何字典来创建相同的json) –

+0

@ L.B这个应用程序不是基于web的,我使用JSON进行序列化,以实现其他商业原因。数据不会被外部系统处理。 –

+0

这只是一个例子来解释逻辑。 json的接收者不知道你是如何创建它的。它甚至不知道你用来创建它的语言。所以你做出错误的假设 –

回答

2

你可以还填充现有对象与PopulateObject

var dict = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 

dict["x"] = new Dictionary<string, string>(); 
dict["x"]["y"] = "something"; 

var json = JsonConvert.SerializeObject(dict); 


var result = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 
JsonConvert.PopulateObject(json, result); 

Console.WriteLine(result["x"]["y"]); 
Console.WriteLine(result.Comparer == dict.Comparer ? "Same" : "Diff"); 

输出:

something 
Same 
+0

谢谢,这正是我需要的。 –

1

如果传递两个要使用到新字典的构造函数的反序列化的结果和比较器可以指定在你的字典的构造函数使用比较器:

var unSerialized = 
    new Dictionary<string, Dictionary<string, string>> 
     (JsonConvert 
      .DeserializeObject<Dictionary<string, Dictionary<string, string>>>(serialized), 
      dict.Comparer); 
+0

谢谢,我没有想到将它作为字典的构造函数中的集合返回。 –

2

这可能有点迟,但可以使用JsonConverter来扩展生成的JSON会稍微复杂一些,但是更加灵活。我创建了所描述的情形下的样品,它不是完全
.NET Fiddle - Try It
(随意扩展,如果你决定使用它):

public class DictConverter<TValue> : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return true; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var obj = JToken.ReadFrom(reader);     
     if (objectType == typeof(Dictionary<string, TValue>)) 
     { 
      var comparer = obj.Value<string>("Comparer"); 
      Dictionary<string, TValue> result; 
      if (comparer == "OrdinalIgnoreCase") 
      { 
       result = new Dictionary<string, TValue>(StringComparer.OrdinalIgnoreCase); 
      } 
      else 
      { 
       result = new Dictionary<string, TValue>(); 
      } 
      obj["Comparer"].Parent.Remove(); 
      serializer.Populate(obj.CreateReader(), result); 
      return result; 
     } 
     return obj.ToObject(objectType); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var obj = JObject.FromObject(value); 
     if (value is Dictionary<string, TValue>) 
     { 
      if((value as Dictionary<string, TValue>).Comparer == StringComparer.OrdinalIgnoreCase) 
       obj.Add("Comparer", JToken.FromObject("OrdinalIgnoreCase")); 
     } 
     obj.WriteTo(writer); 

    } 
} 

和使用

var dict = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); 

dict["x"] = new Dictionary<string, string>(); 
dict["x"]["y"] = "something"; 

var serialized = JsonConvert.SerializeObject(dict, 
    new DictConverter<Dictionary<string,string>>()); 
var unSerialized = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>> 
    (serialized, new DictConverter<Dictionary<string, string>>());