【问题标题】:Deserialize JSON Dictionary with StringComparer使用 StringComparer 反序列化 JSON 字典
【发布时间】:2025-11-24 02:45:01
【问题描述】:

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

这是我遇到的问题的代码 sn-p:

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&lt;TKey, TValue&gt;.Comparer 是只读的。

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

【问题讨论】:

  • 好的,Ron,假设您将此 json 发送到另一个站点。它怎么知道你是如何构造这个字典的(你甚至可以使用其他没有任何字典的方法来创建相同的 json)
  • @L.B 此应用程序不是基于 Web 的,出于其他业务原因,我使用 JSON 通过 XML 进行序列化。数据不会由外部系统处理。
  • 只是举例说明逻辑。 json 的接收者不知道你是如何创建它的。它甚至不知道你用来创建它的语言。所以你做出了错误的假设
  • 我不确定我是否理解,系统是独立的,它使用 JSON 仅用于数据的文件持久化,而不是传输到另一个系统。 JSON 的接收者也始终是它的生产者。问题是在运行时我需要以不区分大小写的方式比较字典中的键,但我无法使用不区分大小写的比较器检索字典。
  • 假设你 DeserializeObject 使用这个 json {"prop1:"val1"}。它可以是字典,也可以是具有单个属性的类。它可以用任何比较器序列化。所以JsonConvert.DeserializeObject无从得知。

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    var deserialized = JsonConvert
        .DeserializeObject<Dictionary<string, Dictionary<string, string>>>(serialized);
    
    var withComparer = new Dictionary<string, Dictionary<string, string>> (
        deserialized, StringComparer.OrdinalIgnoreCase);
    

    【讨论】:

    • 谢谢,没想到在字典的构造函数中把它作为集合返回。
    【解决方案3】:

    可能有点晚了,但是可以使用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>>());
    

    【讨论】:

      最近更新 更多