使用 StringComparer 反序列化 JSON 字典

Ron*_*yer 11 c# dictionary desktop-application json.net

我正在尝试序列化/反序列化字典,问题是我用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"));
Run Code Online (Sandbox Code Playgroud)

( .NET Fiddle - 试试看)

在控制台打印出以下内容:

Different

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

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

Xia*_*312 13

您还可以使用以下内容填充现有对象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");
Run Code Online (Sandbox Code Playgroud)

输出:

something
Same
Run Code Online (Sandbox Code Playgroud)


Ruf*_*s L 9

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

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

var withComparer = new Dictionary<string, Dictionary<string, string>> (
    deserialized, StringComparer.OrdinalIgnoreCase);
Run Code Online (Sandbox Code Playgroud)


ASp*_*rin 5

可能有点晚了,但是可以使用扩展生成的 JSON,虽然JsonConverter会更复杂一些,但更灵活。我已经为所描述的情况创建了一个示例,它不是完整的
.NET Fiddle - 尝试一下
(如果您决定使用它,请随意扩展):

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

    }
}
Run Code Online (Sandbox Code Playgroud)

和用途

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>>());
Run Code Online (Sandbox Code Playgroud)