C# 从 JSON 反序列化 KeyValuePair

huangapple go评论87阅读模式
英文:

C# deserialize KeyValuePair from JSON

问题

这是问题的绝对最简版本之一(其中的一个子集)。

public class Subscription
{
    public bool HasRead { get; set; } = true;
    public string TimeStamp { get; set; } = "";
}

public static void Main()
{
    // 这种输入格式是必需的。不能更改。
    string json = @"
        {
            ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
                ""hasRead"": true,
                ""Timestamp"": ""XXX""
            }
        }";

    // 我试图找到在C#中正确的反序列化类型
    var deser = JsonSerializer.Deserialize<KeyValuePair<string, Subscription>>(json,
        new JsonSerializerOptions(JsonSerializerDefaults.Web));

    // System.Text.Json.JsonException: 
    // 'The JSON value could not be converted to 
    // System.Collections.Generic.KeyValuePair
}
英文:

This is the absolute simplest version of this question (a subset of it).

using System;
using System.Collections.Generic;
using System.Text.Json;


public class Program
{
    public class Subscription
    {
        public bool HasRead { get; set; } = true;
        public string TimeStamp { get; set; } = &quot;&quot;;
    }



    public static void Main()
    {
        // this input format is a requirement. It cannot be changed.
        string json = @&quot;
		  {
			&quot;&quot;305FDF11-25E7-43DE-B09D-DFFC17C79599&quot;&quot;: {
			  &quot;&quot;hasRead&quot;&quot;: true, // EDIT: Removed the double quotes around the boolean. That was not the core issue.
			  &quot;&quot;Timestamp&quot;&quot;: &quot;&quot;XXX&quot;&quot;
			}
		  }
		&quot;;

        // I&#39;m trying to find the correct deserialization type in C#
        var deser = JsonSerializer.Deserialize&lt;KeyValuePair&lt;string, Subscription&gt;&gt;(json,
            new JsonSerializerOptions(JsonSerializerDefaults.Web));

        // System.Text.Json.JsonException: 
        //&#39;The JSON value could not be converted to 
        //System.Collections.Generic.KeyValuePair
    }
}

I can't understand why that can't be deserialized.

Note: I'm obsessing over the KeyValuePair type but maybe it has to do with the casing of the fields or something else obvious.

Other note : It still fails when I change KeyValuePair&lt;string, Subscription&gt; to KeyValuePair&lt;string, object&gt; to make it more permissive.

答案1

得分: 1

首先,你的 JSON 不符合 KeyValuePair<string, Subscription> 的默认序列化,建议将类型更改为 Dictionary<string, Subscription>。此外,默认的 JSON 反序列化器无法反序列化你的 JSON,建议使用 Newtonsoft.Json

using Newtonsoft.Json;

string json = @"
              {
                ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
                  ""hasRead"": ""true"",
                  ""Timestamp"": ""XXX""
                }
              }
            ";

var deserialized = JsonConvert.DeserializeObject<Dictionary<string, Subscription>>(json);
var subscription = deserialized["305FDF11-25E7-43DE-B09D-DFFC17C79599"];
Console.WriteLine($"Subscription timestamp is {subscription.TimeStamp}");
英文:

First of all, your JSON does not conform to default serialization of KeyValuePair&lt;string, Subscription&gt;, I'd recommend switching the type to Dictionary&lt;string, Subscription&gt;. As well, default JSON deserializer is unable to deserialize your JSON. I'd recommend using Newtonsoft.Json

using Newtonsoft.Json;

string json = @&quot;
          {
            &quot;&quot;305FDF11-25E7-43DE-B09D-DFFC17C79599&quot;&quot;: {
              &quot;&quot;hasRead&quot;&quot;: &quot;&quot;true&quot;&quot;,
              &quot;&quot;Timestamp&quot;&quot;: &quot;&quot;XXX&quot;&quot;
            }
          }
        &quot;;

var deserialized = JsonConvert.DeserializeObject&lt;Dictionary&lt;string, Subscription&gt;&gt;(json);
var subscription = deserialized[&quot;305FDF11-25E7-43DE-B09D-DFFC17C79599&quot;];
Console.WriteLine($&quot;Subscription timestamp is {subscription.TimeStamp}&quot;);

Like this you'd get output of Subscription timestamp is XXX.

答案2

得分: 1

你有两个问题。

public bool HasReadBool => bool.Parse(HasRead);
var deser = JsonSerializer.Deserialize<Dictionary<string, Subscription>>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web));
var kvp = deser.First();
英文:

You have two issues.

      string json = @&quot;
      {
        &quot;&quot;305FDF11-25E7-43DE-B09D-DFFC17C79599&quot;&quot;: {
          &quot;&quot;hasRead&quot;&quot;: &quot;&quot;true&quot;&quot;,
          &quot;&quot;Timestamp&quot;&quot;: &quot;&quot;XXX&quot;&quot;
        }
      }
    &quot;;

true is surrounded by quotes. By default that will not deserialise to a boolean but a string. You can change the type of HasRead in the Subscription class to fix the issue. If you want a boolean property then you could add something like:

public bool HasReadBool =&gt; bool.Parse(HasRead);

2)

You cannot deserialise directly to a KeyValuePair as that has named Key and Value properties. Instead you can deserialise to a Dictionary:

 var deser = JsonSerializer.Deserialize&lt;Dictionary&lt;string, Subscription&gt;&gt;(json,
        new JsonSerializerOptions(JsonSerializerDefaults.Web));

If you want to get a KeyValuePair you can do this: var kvp = deser.First()

答案3

得分: 1

以下是您提供的代码的中文翻译:

using System;
using System.Collections.Generic;
using System.Text.Json;

public class Program
{
    public class Subscription
    {
        public bool HasRead { get; set; } = true;
        public string TimeStamp { get; set; } = "";
    }

    public static void Main()
    {
        // 此输入格式是必需的,不能更改。
        string json = @"
          {
            ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
              ""hasRead"": ""true"",
              ""Timestamp"": ""XXX""
            }
          }
        ";

        // 反序列化JSON字符串为字典
        var dict = JsonSerializer.Deserialize<Dictionary<string, Subscription>>(json,
            new JsonSerializerOptions(JsonSerializerDefaults.Web));

        // 遍历字典并打印每个键值对
        foreach (var kvp in dict)
        {
            Console.WriteLine($"Key: {kvp.Key}");
            Console.WriteLine($"HasRead: {kvp.Value.HasRead}");
            Console.WriteLine($"TimeStamp: {kvp.Value.TimeStamp}");
        }
    }
}

希望这有助于您理解代码的中文翻译。

英文:
using System;
using System.Collections.Generic;
using System.Text.Json;

public class Program
{
    public class Subscription
    {
        public bool HasRead { get; set; } = true;
        public string TimeStamp { get; set; } = &quot;&quot;;
    }

    public static void Main()
    {
        // this input format is a requirement. It cannot be changed.
        string json = @&quot;
          {
            &quot;&quot;305FDF11-25E7-43DE-B09D-DFFC17C79599&quot;&quot;: {
              &quot;&quot;hasRead&quot;&quot;: &quot;&quot;true&quot;&quot;,
              &quot;&quot;Timestamp&quot;&quot;: &quot;&quot;XXX&quot;&quot;
            }
          }
        &quot;;

        // deserialize the JSON string into a dictionary
        var dict = JsonSerializer.Deserialize&lt;Dictionary&lt;string, Subscription&gt;&gt;(json,
            new JsonSerializerOptions(JsonSerializerDefaults.Web));

        // iterate over the dictionary and print each key-value pair
        foreach (var kvp in dict)
        {
            Console.WriteLine($&quot;Key: {kvp.Key}&quot;);
            Console.WriteLine($&quot;HasRead: {kvp.Value.HasRead}&quot;);
            Console.WriteLine($&quot;TimeStamp: {kvp.Value.TimeStamp}&quot;);
        }
    }
}

答案4

得分: 1

We can use type Dictionary<String,Subscription> to achieve it.

using System.Text.Json;

class JsonTest
{
    public class Subscription
    {
        public bool HasRead { get; set; } = true;
        public string TimeStamp { get; set; } = "";
    }
    public static void Main()
    {
        string json = @"
             {
                 ""305FDF11-25E7-43DE-B09D-DFFC17C79599"": {
                      ""hasRead"": ""true"",
                      ""TimeStamp"": ""XXX""
                  }
             }
             ";

        var deser = JsonSerializer.Deserialize<Dictionary<string, Subscription>>(json);
        foreach (var key in deser.Keys)
        {
            Subscription subscription = deser[key];
            Console.WriteLine($"Key:{key} HasRead:{subscription.HasRead} TimeStamp:{subscription.TimeStamp}");
        }
    }
}

I tried to print all values.
Output is: -

Key:305FDF11-25E7-43DE-B09D-DFFC17C79599 HasRead:True TimeStamp:XXX

Note: - We should try to match case in JSON and class properties. Else, we will get null/default values. I have modified Timestamp to TimeStamp in JSON string.

英文:

We can use type Dictionary<String,Subscription> to achieve it.

using System.Text.Json;

class JsonTest
{
    public class Subscription
    {
        public bool HasRead { get; set; } = true;
        public string TimeStamp { get; set; } = &quot;&quot;;
    }
    public static void Main()
    {
        string json = @&quot;
             {
                 &quot;&quot;305FDF11-25E7-43DE-B09D-DFFC17C79599&quot;&quot;: {
                      &quot;&quot;hasRead&quot;&quot;: &quot;&quot;true&quot;&quot;,
                      &quot;&quot;TimeStamp&quot;&quot;: &quot;&quot;XXX&quot;&quot;
                  }
             }
             &quot;;

        var deser = JsonSerializer.Deserialize&lt;Dictionary&lt;string, Subscription&gt;&gt;(json);
        foreach(var key in deser.Keys)
        {
            Subscription subscription = deser[key];
            Console.WriteLine($&quot;Key:{key} HasRead:{subscription.HasRead} TimeStamp:{subscription.TimeStamp}&quot;);
        }
    }
}

I tried to print all values.
Output is :-

Key:305FDF11-25E7-43DE-B09D-DFFC17C79599 HasRead:True TimeStamp:XXX

Note :- We should try to match case in json and class properties. Else, We will get null/default values. I have modified Timestamp to TimeStamp in JSON string.

答案5

得分: -1

The default serialization of type KeyValuePair<string, Subscription> looks like this:

{
    "key": "305FDF11-25E7-43DE-B09D-DFFC17C79599",
    "value":{
     "hasRead":true,
     "timeStamp":"XXX"
    }
}

To change this behavior, you need to write your own converter derived from JsonConverter class.
Also note that true value should be without quotes.

英文:

The default serialization of type KeyValuePair<string, Subscription> looks like this:

{
    &quot;key&quot;:
      &quot;305FDF11-25E7-43DE-B09D-DFFC17C79599&quot;,
    &quot;value&quot;:{
     &quot;hasRead&quot;:true,
     &quot;timeStamp&quot;:&quot;XXX&quot;
    }
}

To change this behavior you need to write your own converter derrived from JsonConverter class.
Also note that true value should be without quotes.

huangapple
  • 本文由 发表于 2023年4月19日 19:26:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76053934.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定