Home > Software design >  Json conversion conundrum due to mixed type in List
Json conversion conundrum due to mixed type in List

Time:12-16

All - I've stumbled into a scenario that's causing me quite a bit of grief. I have a json structure (produced by gateio api) which on the face of it, looks super simple to deserialize into an object. the jsonTickerString looks like the below:

{
   "method":"ticker.update",
   "params":[
      "BTC_USDT",
      {
         "period":86400,
         "open":"46721.06",
         "close":"48130.43",
         "high":"48758.59",
         "low":"46330.3",
         "last":"48130.43",
         "change":"2.95",
         "quoteVolume":"2246.8399550054",
         "baseVolume":"106183751.468785134437"
      }
   ],
   "id":null
}

However, this is proving to be deceptively funky when trying to push it into an object model. I derived the object model below and thought we were all set to go:

    public partial class GateIoTicker
    {
        [JsonProperty("method")]
        public string Method { get; set; }

        [JsonProperty("params")]
        public List<ParamElement> Params { get; set; }

        [JsonProperty("id")]
        public object Id { get; set; }
    }

    public class ParamClass
    {
        [JsonProperty("period")]
        public long Period { get; set; }

        [JsonProperty("open")]
        public string Open { get; set; }

        [JsonProperty("close")]
        public string Close { get; set; }

        [JsonProperty("high")]
        public string High { get; set; }

        [JsonProperty("low")]
        public string Low { get; set; }

        [JsonProperty("last")]
        public string Last { get; set; }

        [JsonProperty("change")]
        public string Change { get; set; }

        [JsonProperty("quoteVolume")]
        public string QuoteVolume { get; set; }

        [JsonProperty("baseVolume")]
        public string BaseVolume { get; set; }
    }

    public partial struct ParamElement
    {
        public string coinName;
        public ParamClass quoteParams;

        public static implicit operator ParamElement(ParamClass quoteparams)
        {
            return new ParamElement { quoteParams = quoteparams };
        }
        public static implicit operator ParamElement(string coinname)
        {
            return new ParamElement { coinName = coinname };
        }
    }

I then set about populating the object using the standard Json.Net approach:

var gateIoTicker = JsonConvert.DeserializeObject<GateIoTicker>(jsonTickerString);

However, although this correctly deserializes the string element in the "params" object, no amount of coersion will bring about a deserialization of the ParamClass object.

Am I missing something very obvious here?? I've spent an inordinate amount of time trying to figure this out and think it's now time to solicit some superior brain power.

Hope this scans as expected...

[Edit] - further to Serge's suggestion, i took his code and added it as a method on my GatIoTicker object. Would have preferred an option that desrializes using attributes, but this works perfectly. Refactored code looks like:

    public partial class GateIoTicker
    {
        [JsonProperty("method")]
        public string Method { get; set; }

        [JsonProperty("params")]
        public List<ParamElement> Params { get; set; }

        [JsonProperty("id")]
        public object Id { get; set; }

        public GateIoTicker FromJson(string json)
        {
            var jsonObject = JObject.Parse(json);
            var pars = jsonObject["params"] as JArray;
            var paramElement = new ParamElement();

            foreach (var jObject in pars)
            {
                if (jObject.GetType().Name.ToString() == "JValue") paramElement.ParamName = ((JValue)jObject).ToString();
                else
                {
                    paramElement.ParamBody = jObject.ToObject<ParamClass>();
                }
            }

            GateIoTicker gateIoTicker = new GateIoTicker { Params = new List<ParamElement>() };
            gateIoTicker.Id = (string)jsonObject["Id"];
            gateIoTicker.Method = (string)jsonObject["method"];
            gateIoTicker.Params.Add(paramElement);

            return gateIoTicker;
        }
    }

    public partial class ParamElement
    {
        public string ParamName { get; set; }
        public ParamClass ParamBody {get; set;}
    }

thanks again for the suggestions and nudges. seasons greetings

CodePudding user response:

Try this, it was tested in Visual studio

    var jsonObject = JObject.Parse(json);

    var pars = jsonObject["params"] as JArray;
    
    var paramElement = new ParamElement();

    foreach (var jObject in pars)
    {
        if (jObject.GetType().Name.ToString() == "JValue") paramElement.ParamName = ((JValue)jObject).ToString();
        else
        {
            paramElement.ParamBody=jObject.ToObject<ParamClass>();
        }
    }

    GateIoTicker gateIoTicker = new GateIoTicker {Params= new List<ParamElement>()};
    gateIoTicker.Id= (string) jsonObject["Id"];
    gateIoTicker.Method= (string) jsonObject["method"];
    gateIoTicker.Params.Add(paramElement);

ParamElement class

public partial class ParamElement
{
    public string ParamName { get; set; }
    public ParamClass ParamBody {get; set;}

}
  • Related