繁体   English   中英

C# - 将 JSON 反序列化为 ValueTuple

[英]C# - deserialize JSON into ValueTuple

我正在尝试将[{"foo": "1", "bar": false}, {"foo": "2", "bar": false}] List<(string, bool)>化为List<(string, bool)>类型:

JsonConvert.DeserializeObject<List<(string foo, bool bar)>>(json)  

但总是得到一个默认值列表 - (null, false)

如何实现正确的反序列化?

PS 我对此目的的任何模型/类都不感兴趣。 我需要确切的值元组。

创建 C# 元组功能是为了表示值集,而不是实体。

值的名称类似于变量的名称。 与变量名称一样,元组值名称仅存在于源代码中。

(string foo, bool bar)实际上只是ValueTuple<string, int> 就像(string bar, bool foo)

(string foo, bool bar) a = ('one', true);
(string bar, bool foo) b = a;

元组值存储在名为Item1Item2等的字段中。

在这里亲自看看它是如何工作的。

如果您热衷于为此使用值元组,则必须对自己进行反序列化:

var json = "[{\"foo\": \"1\", \"bar\": false}, {\"foo\": \"2\", \"bar\": false}]";

var jArray = JsonConvert.DeserializeObject<JArray> (json);

var list = new List<(string foo, bool bar)>();

foreach (var item in jArray)
{
    list.Add((item.Value<string>("foo"), item.Value<bool>("bar")));
}

在 C#9 中,您可以创建一个record并使用生成的解构函数来创建一个 ValueTuple。 我确实看到您不想声明模型,但这是我发现的最接近的方法:

声明记录:

private record FooBar(string foo, bool bar);

反序列化和解构:

(string foo, bool bar) = JsonConvert.DeserializeObject<FooBar>(json);

或者

var (foo, bar) = JsonConvert.DeserializeObject<FooBar>(json);

实现它的一种方法是使用 JsonConverter。 例如,

public class ValueTupleConverter<U,V> : Newtonsoft.Json.JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(ValueTuple<U,V>) == objectType;
    }

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

        var jObject = Newtonsoft.Json.Linq.JObject.Load(reader);
        var properties = jObject.Properties().ToList();
        return new ValueTuple<U, V>(jObject[properties[0].Name].ToObject<U>(), jObject[properties[1].Name].ToObject<V>());
    }

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

}

现在您可以按如下方式使用转换器。

var json = "[{'foo': '1', 'bar': false}, {'foo': '2', 'bar': false}]";
var result = JsonConvert.DeserializeObject<IEnumerable<(string,bool)>>(json,new ValueTupleConverter<string,bool>());
foreach(var (foo,bar) in result)
{
   Console.WriteLine($"foo:{foo},bar:{bar}");
}

样本输出

foo:1,bar:False
foo:2,bar:False

我建议先将JSON转换为模型并Deserialize json

public class item
{
    public string foo { get; set; }
    public bool bar { get; set; }
}

方法 1 - 使用foreach

using (StreamReader r = new StreamReader(filepath))
{
     string json = r.ReadToEnd();
     var obj = JsonConvert.DeserializeObject<List<item>>(json);

     Dictionary<string, bool> keyValuePairs = new Dictionary<string, bool>();
     foreach (var keyvalue in obj)
     {
          if (!keyValuePairs.ContainsKey(keyvalue.foo))
             keyValuePairs.Add(keyvalue.foo, keyvalue.bar);
     }
}

方法 2 - 使用LINQ而不用担心重复

Dictionary<string, bool> keyValuePairs = JsonConvert.DeserializeObject<IEnumerable<item>>(json).ToDictionary(x => x.foo, x => x.bar);

方法 3 - 通过考虑重复使用LINQ

Dictionary<string, bool> keyValuePairs = JsonConvert
                .DeserializeObject<IEnumerable<item>>(json)
                .GroupBy(p=>p.foo, StringComparer.OrdinalIgnoreCase)
                .ToDictionary(x => x.First().foo, x => x.First().bar);

方法 4 - 使用DeserializeAnonymousType

 var definition = new[] {new { foo = "", bar = false } };
 string json = @"[{'foo': '1', 'bar': false}, {'foo': '2', 'bar': true}]";
 var obj = JsonConvert.DeserializeAnonymousType(json, definition).Select(p=> (p.foo, p.bar)).ToList();

您应该创建对象以反序列化

要在C#中反序列化Json,可能这是最好的方法。

从json创建模型,

public class Model
{
    public string foo { get; set; }
    public bool bar { get; set; }
}

使用该模型通过Newtonsoft Json反序列

List<Model> data = JsonConvert.DeserializeObject<List<Model>>(jsonString);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM