Home > Blockchain >  Convert json property value of string to custom object
Convert json property value of string to custom object

Time:12-26

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?

CodePudding user response:

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>();
  • Related