【问题标题】:Deserialize Nested Dictionary in from Json C#从 Json C# 中反序列化嵌套字典
【发布时间】:2021-10-05 12:56:25
【问题描述】:

我有这样的课

public class A{
    public Guid userId { get; set; }
    public Guid businessId { get; set; }
    public Dictionary<int, long> rights { get; set; }
}

我想把这个json转换成这个类

    {
    "userId": "dc2af693-72e1-49a7-80aa-6416c6536bdf",
    "businessId": "0110eea4-7a47-4a7c-95ea-10547ab49652",
    "rights": "{\"19\":1,\"17\":15,\"18\":1,\"23\":1,\"1\":31,\"20\":3,\"3\":1,\"16\":0}",
   }

但是当我尝试用 NewtonSoft.Json 转换它时

JsonConvert.DeserializeObject<A>(json);

我收到以下错误无法将 System.string 转换为 System.Dictionary 发生的事情是我的权利被转换为类似这样的字符串

"{"19":1, "17":15, "18":1, ..., "16":0}"

如果我再次反序列化这个字符串,它会按照我的意愿工作,是否有更好的方法来做到这一点。

【问题讨论】:

  • 其实“rights”的内容是一个字符串,因为所有的引号都被反斜杠(\")转义了
  • 您是否尝试过创建示例对象并首先对其进行序列化以查看序列化后的样子?我发现这是在构建复杂字符串时发现一些更容易遗漏的错误的好方法。
  • rights 中的数据实际上是字典的 Json 表示,因此这可能是一个两步过程:首先将 rights 反序列化为字符串,然后再将其反序列化为字典: Dictionary&lt;int, long&gt; RightValues =&gt; JsonConvert.DeserializeObject&lt;Dictionary&lt;int, long&gt;&gt;(rights);
  • @CMGeek 此 json 是 jwt 令牌的有效负载,其中所有内容都作为对令牌用户的声明添加。
  • 您需要使用自定义 JsonConverter 来装饰 rights 属性 - 在自定义 JsonConverter 中,您将能够反序列化字符串,然后将其转换为字典。跨度>

标签: c# asp.net-core json.net


【解决方案1】:

由于rights 是字符串格式,您可以添加自定义JsonConverter 将字符串转换为字典

public class A
{
    public Guid userId { get; set; }
    public Guid businessId { get; set; }
    [JsonConverter(typeof(RightsSerializer))]
    public Dictionary<int, long> rights { get; set; }
}

这里是 RightsSerializer

public class RightsSerializer : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Dictionary<int, long>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null) return null;

        var jt = JToken.Load(reader);
        return JsonConvert.DeserializeObject<Dictionary<int, long>>(jt.Value<String>());
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

反序列化对象

var json = File.ReadAllText("json1.json");
var result = JsonConvert.DeserializeObject<A>(json);

【讨论】:

  • 我目前正在这样做,但是该类的作用域是我可以在任何地方注入以获取值的,我的类包含字典的地方没有任何简写。
  • @MuhammadJamali,那么您需要自定义运行时序列化程序。更新帖子以反映相同
【解决方案2】:

将类更改为类似这样会有所帮助。尽管你需要让代码比这更好。

        public class A
    {
        public Guid userId { get; set; }
        public Guid businessId { get; set; }

        //[JsonConverter(typeof(Dictionary<int, long>))]
        public string rights { get; set; }

        public Dictionary<int, long> rightss => JsonConvert.DeserializeObject<Dictionary<int, long>>(rights);
    }

【讨论】:

    【解决方案3】:

    你不能不反序列化两次,但你可以用一个私有子类隐藏它。

    public class A {
       public Guid userId {get;set;}
       public Guid businessId {get;set;}
       public Dictionary<int, long> rights {get;set;}
    
       private class B {
          public Guid userId {get;set;}
          public Guid businessId {get;set;}
          public string rights {get;set;}
       }
    
       private B b;
    
       public A (string json) {
          var o = new JsonSerializerOptions();
          o.AllowTrailingCommas = true;
          b = JsonSerializer.Deserialize<B>(json, o);
          userId = b.userId;
          businessId = b.businessId;
          rights = JsonSerializer.Deserialize<Dictionary<int, long>>(b.rights,o);
       }
    }
    

    在小提琴中与测试一起使用:

    Fiddle

    【讨论】:

      猜你喜欢
      • 2022-01-22
      • 1970-01-01
      • 2014-02-19
      • 2011-09-18
      • 2011-06-03
      • 2020-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多