使用 System.Text.Json 反序列化为不区分大小写的字典

Deserialize into a case-insensitive dictionary using System.Text.Json

我正在尝试将 json 反序列化为 属性 类型 Dictionary<string,string> 的对象。我将词典的比较器指定为 StringComparer.OrdinalIgnoreCase。 这是 class:

class  DictionaryTest
{
       public Dictionary<string, string> Fields { get; set; }
       public DictionaryTest()
       {
           Fields = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
       }
}

但是当反序列化发生时,比较器被更改为通用的。因此,我无法以不区分大小写的方式访问我的字典的键。

            var points = new Dictionary<string, string>
            {
                { "James", "9001" },
                { "Jo", "3474" },
                { "Jess", "11926" }
            };

            var testObj = new {Fields = points};           
            var dictionaryJsonText =  JsonSerializer.Deserialize<DictionaryTest>(JsonSerializer.Serialize(testObj, options:new JsonSerializerOptions()
            {
                IgnoreNullValues = true,
                WriteIndented = false,
                PropertyNamingPolicy = null,
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
                DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
                PropertyNameCaseInsensitive = true
            }));

            string nameJsonText = "", nameJsonText2="";
            //Because of the naming policy specified above, the keys are camelCase. 
            //So keys are james, jo and jess
            //I expect to be able to access either james, or James as keys. 
            dictionaryJsonText?.Fields.TryGetValue("James", out nameJsonText);
            dictionaryJsonText?.Fields.TryGetValue("james", out nameJsonText2);
            Console.WriteLine($"Name with system.text.json is:  {nameJsonText}");
            Console.WriteLine($"Name with system.text.json is:  {nameJsonText2}");
            Console.WriteLine($"Comparer is {dictionaryJsonText?.Fields.Comparer}");

那么如何将 json 反序列化为如下所示的 class 并保持其不区分大小写?有什么建议么?我正在使用 .net5。 我应该提一下,这段代码使用 Newtonsoft 可以完美地工作。比较器将保持为 OrdinalIgnoreCase 并且不区分大小写。

目前没有办法做你想做的事。但是,您可以自己实现该功能。

您可以针对此特定案例创建自定义 JsonConverter。例如:

public sealed class CaseInsensitiveDictionaryConverter<TValue>
    : JsonConverter<Dictionary<string, TValue>>
{
    public override Dictionary<string, TValue> Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options)
    {
        var dic = (Dictionary<string, TValue>)JsonSerializer
            .Deserialize(ref reader, typeToConvert, options);
        return new Dictionary<string, TValue>(
            dic, StringComparer.OrdinalIgnoreCase);
    }

    public override void Write(
        Utf8JsonWriter writer,
        Dictionary<string, TValue> value,
        JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(
            writer, value, value.GetType(), options);
    }
}

然后您可以通过这样做将它绑定到特定的 属性:

class DictionaryTest
{
    [JsonConverter(typeof(CaseInsensitiveDictionaryConverter<string>))]
    public Dictionary<string, string> Fields { get; set; }
        = new Dictionary<string, string>();
}

就是这样。您可以正常反序列化:

var json = JsonSerializer.Serialize(new DictionaryTest
{
    Fields =
    {
        { "One", "Two" },
        { "Three", "Four" }
    }
});
var dictionaryJsonText = JsonSerializer.Deserialize<DictionaryTest>(json);

以上示例将生成一个包含不区分大小写的键的字典。