ValueTuples lose their property names when serialized
Asked Answered
C

3

30

While trying to serialize a named value tuple to JSON string, it loses the names assigned to items

(string type, string text) myTypes = ("A", "I am an animal");
var cnvValue = JsonConvert.SerializeObject(myTypes);

I am expecting the serialized value as

{"type":"A","text":"I am an animal"}

but the actual results are

{"Item1":"A","Item2":"I am an animal"}

There are two things that i am interested to know

  • Why does it behave like that
  • How to get the expected output
Curren answered 28/1, 2019 at 8:20 Comment(1)
FYI github.com/JamesNK/Newtonsoft.Json/issues/1505Boatel
A
26

How to get the expected output

Something like this:

var myTypes = new{ type = "A", text = "I am an animal"};
var cnvValue = JsonConvert.SerializeObject(myTypes);

should work if you’re looking for a similarly terse approach. Doesn’t use ValueTuples (but anonymous types) under the hood though; this is my interpreting your question as “how can I produce this expected JSON without going to the full extent of declaring a class etc”

Adenoma answered 28/1, 2019 at 8:41 Comment(1)
You interpreted it in the correct sense. I used ValueTuples to do exactly that.Curren
E
20

The names are a compiler trick. If you look at the definition for ValueTuple you'll see that its field names are just Item1, Item2, etc.

Since JsonConvert.SerializeObject was compiled well before you assigned names that you could use during your compilation, it cannot recover the names.

Method parameters/return types are decorated with attributes that indicate the names to be used when a method's signature includes ValueTuples. This allows code authored later to "see" the names by the compiler playing tricks again, but that's the "wrong way around" to be of much use here.

How to get the expected output

Introduce an explicit type, if the names of the fields/properties are so important.

Egress answered 28/1, 2019 at 8:23 Comment(4)
Important to note that the explicit type could be an anonymous type.Bathymetry
@AvnerShahar-Kashtan Anonymous type are not explicit anywayCentipede
I do not want to create an explicit type to use it only once. But still I want the names of items to appear in JSON string.Curren
If you want the better names, you need to at least use an anonymous type, or a named type. ValueTuple will not help you, as you've seen.Specification
L
3

How to get the expected output

Use explicit custom type or anonymous class like in @Caius answer.

Or don't create special type for it at all (for anonymous type compiler generates class behind the scene for you) and use JObject to dynamically create json:

var myTypesJson = new JObject(
    new JProperty("type", "A"), 
    new JProperty("text", "I am an animal")
);
var cnvValue = myTypesJson.ToString();

or use indexer and initialization syntax for it:

var createdJson = new JObject()
{
    ["type"] = "A",
    ["text"] = "I am an animal"
};
var cnvValue = createdJson.ToString();
Lodovico answered 3/2, 2019 at 23:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.