使用StringComparer反序列化JSON字典

时间:2017-09-25 20:09:19

标签: c# dictionary json.net desktop-application

我正在尝试序列化/反序列化字典,问题是我使用StringComparer.OrdinalIgnoreCase比较器创建字典。

以下是我遇到的问题的代码段:

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序列化程序没有序列化我在创建字典时设置的Comparer,但问题是由于Dictionary<TKey, TValue>.Comparer是只读的,因此无法设置Comparer。

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

3 个答案:

答案 0 :(得分:3)

您还可以使用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

答案 1 :(得分: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>>());

答案 2 :(得分:1)

如果将反序列化的结果和要使用的比较器都传递给新字典的构造函数,则可以指定要在字典的构造函数中使用的比较器:

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