3

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

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

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

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

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

4

4 回答 4

5

创建 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;

元组值存储在名为 的字段Item1中,Item2依此类推。

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

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

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")));
}
于 2019-11-29T19:47:13.143 回答
5

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

于 2020-11-17T16:51:07.043 回答
1

实现它的一种方法是使用 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
于 2019-11-29T15:22:05.153 回答
0

我建议先转换JSON为模型和Deserializejson

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

方法二——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();
于 2019-11-29T10:58:26.963 回答