0

I have some JSON data, which I wish to deserialize into a C# object.

The data looks like this:

{
    "version": 0,
    "guid": "2166a7d5744d47009adaa29f0e549696",
    "csv": "one:1,two:2,three:3",
    "method": "substract"
}

The "csv" property is giving me trouble, as I want it to be deserialized to the following csv object (it's content can change, so it can have more or less comma-separated values):

public class CSV
{
    public int One {get;set;}
    public bool Two {get;set;}
    public int Three {get;set;}
}

I already have an object for the bigger JSON:

public class MyJsonData
{
    public int Version {get;set;}
    public string Guid {get;set;}
    public string Csv {get;set;}
    public string Method {get;set;}
}

But I just can't figure out how to parse the comma-separated string to my CSV object.

I tried adding a public CSV (string s) constructor to the CSV object and changing the type from string to CSV in the MyJsonData object, hoping C# would use that constructor (I'm using System.Text.Json) but it didn't and it threw an exception.

The only thing I can come up is separating the string by commas and using reflection to fill the CSV object properties (I've defined all possible values the string can have and expect the missing ones to be empty or have the default value for the type). But I'm looking for a more elegant solution, as I am accessing the MyJsonData object everywhere in my code, so having to separately handle a CSV object seems cumbersome and a worst-practice.

Is there any way to tell JSON what method to use to convert the string to my CSV object when deserializing?

6
  • "Elegant" is not a testable attribute of an answer on Stack Overflow. Microsoft provides documentation on how to create custom converters for System.Text.Json There are also many questions which detail their use; e.g. How can I create a custom converter similar to Newtonsoft using system.text.json? Commented Dec 23, 2022 at 20:30
  • Your json is not valid. Can you post the valid one pls? Commented Dec 23, 2022 at 21:22
  • @Serge, sorry missed a quote character, it should be fine, now. Commented Dec 23, 2022 at 21:45
  • @HereticMonkey, thanks for the links! I was using abstract thought to convey a deeper meaning through context or "reading between the lines", as it is also called. I thought it was as obvious as can be, but I will try to make it much, much simpler next time. Commented Dec 23, 2022 at 21:47
  • @notarobot Are you determined to use Text.Json? Using Newtonsonft.Json will make the code much more simplle Commented Dec 23, 2022 at 22:56

1 Answer 1

1

If you use Newtonsoft.Json you will need only one more string of code

using Newtonsoft.Json;

MyJsonData myJsonData = JsonConvert.DeserializeObject<MyJsonData>(json);

public class MyJsonData
{
    public CSV Csv { get; set; }
    //...another properties

    [JsonConstructor]
    public MyJsonData(string csv)
    {
        Csv = new JObject(csv.Split(",")
                              .Select(i => i.Split(":"))
                              .Select(r => new JProperty(r[0].ToString(), Convert.ToInt32(r[1]))))
                              .ToObject<CSV>();
    }
}

If you use Text.Json with Net 6+, the shortest code probably is

 var jDoc = JsonNode.Parse(json);

jDoc["csv"] =  new JsonObject( JsonDocument.Parse(json).RootElement
                  .GetProperty("csv").GetString()
                  .Split(",")
                  .Select(r => r.Split(":") )
                  .Select(i=>  KeyValuePair.Create<string, JsonNode>(i[0], Convert.ToInt32(i[1]))));

MyJsonData myJsonData = jDoc.Deserialize<MyJsonData>( new JsonSerializerOptions {PropertyNameCaseInsensitive = true});  

if you want one line of code you will probably wrap this code in a custom formater ( as it is usually in the most cases when you use Text.Json)

UPDATE

if some of CSV properties are boolean, you can try this code

Csv = new JObject(csv.Split(",")
                              .Select(i => i.Split(":"))
                              .Select(r => new JProperty(r[0].ToString(),
       r[1].ToLower() =="true"||r[1].ToLower() =="false"? Convert.ToBoolean( r[1]):
       Convert.ToInt32(r[1]))))
                              .ToObject<CSV>();
Sign up to request clarification or add additional context in comments.

5 Comments

Ah, I see my mistake - when I made a constructor I named the string parameter "s" but the name matters. Thank you! Also Merry Christmas! :) Just one more thing, if I were to change the type of CSV's property "Two" to be bool how should I change the Newtonsoft code?
You are wonderful but, sorry, I should've been more clear that I meant that in the JSON the 1 or 0 values of the "Two" property should be regarded as "true" and "false" and, thus, the CSV class would have a bool "Two" property, as I will edit in my question.
@notarobot I think it will work any way. You have to try and tell me if you have any problem
Yup, it did. I did not believe it but holy smokes, I love C#!!! Thank you a million! And happy holidays! :)
@notarobot Happy Xmas and New Year too!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.