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

问题描述 投票:0回答:3

我正在尝试将 json 反序列化为具有

Dictionary<string,string>
类型属性的对象。我将词典的比较器指定为
StringComparer.OrdinalIgnoreCase
。 这是这门课:

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 DictionaryTest{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}");

enter image description here

enter image description here

那么我该如何将 json 反序列化为如下所示的类并保持其不区分大小写呢?有什么建议么?我正在使用.net5。 我应该提到的是,使用

Newtonsoft
这段代码可以完美地工作。比较器将保留为 OrdinalIgnoreCase 并保留不区分大小写。

c# json-deserialization .net-5 system.text.json
3个回答
11
投票

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

您可以为此特定案例创建自定义

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

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


0
投票

这个问题很老了,但我想说我有更好的解决方案。下面的解决方案不会创建额外的字典,因此内存流量较低。

JsonSerializerOptions JsonSerializerOptions =
    new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        PropertyNameCaseInsensitive = false,
        TypeInfoResolver = new DefaultJsonTypeInfoResolver()
    };

string valuesAsJson =
    """
    {
        "key1": "value1",
        "key2": "value2",
        "key3": "value3",
        "Key1": "value3"
    }
    """;

JsonTypeInfo<Dictionary<string, string?>> jsonTypeInfo =
    JsonTypeInfo.CreateJsonTypeInfo<Dictionary<string, string?>>(
        JsonSerializerOptions
    );

jsonTypeInfo.CreateObject = () => new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);

Dictionary<string, string?>? values =
    JsonSerializer.Deserialize<Dictionary<string, string?>>(

        valuesAsJson,
        jsonTypeInfo
    );

-2
投票

似乎有一个选项可以实现这一目标。

JsonSerializerOptions options = new JsonSerializerOptions
{
       PropertyNameCaseInsensitive = true
};

await JsonSerializer.DeserializeAsync<...>(stream, options)

JsonSerializerOptions.PropertyNameCaseInsensitive 属性

© www.soinside.com 2019 - 2024. All rights reserved.