【问题标题】:Json conversion conundrum due to mixed type in List由于 List 中的混合类型导致的 Json 转换难题
【发布时间】:2022-01-18 06:41:11
【问题描述】:

所有 - 我偶然发现了一个让我非常悲伤的场景。我有一个 json 结构(由 gateio api 生成),从表面上看,它看起来超级简单,可以反序列化为一个对象。 jsonTickerString 如下所示:

{
   "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
}

但是,当尝试将其推入对象模型时,这被证明是看似时髦的。我推导出了下面的对象模型,并认为我们都准备好了:

    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 };
        }
    }

然后我开始使用标准 Json.Net 方法填充对象:

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

然而,尽管这会正确反序列化“params”对象中的字符串元素,但再多的强制也不会导致ParamClass 对象的反序列化。

我在这里遗漏了一些非常明显的东西吗?我花了很多时间试图弄清楚这一点,并认为现在是时候寻求一些卓越的脑力了。

希望扫描按预期进行...

[编辑] - 根据 Serge 的建议,我采用了他的代码并将其作为方法添加到我的 GatIoTicker 对象上。本来更喜欢使用属性反序列化的选项,但这非常有效。重构后的代码如下:

    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;}
    }

再次感谢您的建议和推动。四季问候

【问题讨论】:

  • 或者你可以尝试反序列化为JArray,然后一个一个地反序列化每个子对象
  • 欢呼@Charlieface,看起来它可能会提供一些机会。看了看,对于它如何适应我的场景几乎没有任何线索,所以如果你面临一个小挑战,很想看看它在这个场景中是如何工作的,因为它在很大程度上会有所不同!!跨度>

标签: c# json


【解决方案1】:

试试这个,在 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 类

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

}

【讨论】:

  • 感谢@Serge altho,我可以看到这在编码解决方案方面是有效的(显然确实如此),我曾希望找到一种方法将所有内容隐藏在 JsonConvert 门面后面,因此不必放松多个代码位置中的对象。如果可以将其添加到对象模型并因此以正常方式反序列化(自定义转换器??),我很想看看它会是什么样子。再次感谢您的意见
  • 当然,将其创建为 GateIoTicker 上的方法效果很好,并且可能可以在 JsonConvert 约定之外使用。仍然希望看到正在播放的属性版本:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-20
  • 2011-09-04
  • 2012-08-17
  • 1970-01-01
  • 2021-03-27
  • 2010-09-20
相关资源
最近更新 更多