问题
I'm trying to deserialize [{"foo": "1", "bar": false}, {"foo": "2", "bar": false}]
into List<(string, bool)>
type:
JsonConvert.DeserializeObject<List<(string foo, bool bar)>>(json)
But always get a list of default values - (null, false)
.
How can I achieve correct deserializing?
P.S. I'm not interested in any model/class for that purpose. I need exactly value tuple instead.
回答1:
The C# tuple feature was created to represent sets of values, not entities.
The names of the values are like the names of variables. Like variable names, tuple value names only exist in source code.
(string foo, bool bar)
is, actually, just ValueTuple<string, int>
. just like (string bar, bool foo)
:
(string foo, bool bar) a = ('one', true);
(string bar, bool foo) b = a;
The tuple values are stored in fields named Item1
, Item2
and so on.
See for yourself how it works here.
If you're that keen into using value tuples for that, you'll have to deserialize yourself:
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")));
}
回答2:
One way to achieve it would be to use a JsonConverter. For example,
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);
}
}
Now you can use the Converter as following.
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}");
}
Sample Output
foo:1,bar:False
foo:2,bar:False
回答3:
In C#9 you can create a record
and use the generated deconstructor to create a ValueTuple. I did see that you did not want to declare a model but it is the closest approach I have found:
Declare the record:
private record FooBar(string foo, bool bar);
Deserialize and deconstruct:
(string foo, bool bar) = JsonConvert.DeserializeObject<FooBar>(json);
or
var (foo, bar) = JsonConvert.DeserializeObject<FooBar>(json);
回答4:
I suggest first convert the JSON
to model and Deserialize
the json
public class item
{
public string foo { get; set; }
public bool bar { get; set; }
}
Method 1 - using 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);
}
}
Method 2 - using LINQ
without worrying about duplicates
Dictionary<string, bool> keyValuePairs = JsonConvert.DeserializeObject<IEnumerable<item>>(json).ToDictionary(x => x.foo, x => x.bar);
Method 3 - using LINQ
by considering duplicates
Dictionary<string, bool> keyValuePairs = JsonConvert
.DeserializeObject<IEnumerable<item>>(json)
.GroupBy(p=>p.foo, StringComparer.OrdinalIgnoreCase)
.ToDictionary(x => x.First().foo, x => x.First().bar);
Method 4 - using 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();
来源:https://stackoverflow.com/questions/59103002/c-sharp-deserialize-json-into-valuetuple