c# - 反序列化模式中带有尴尬附加属性的 JSON 数组
问题描述
我在这里有一个与这个问题非常相似的问题,除了我的应用程序是用 C# 编写的,不幸的是我无法弄清楚如何转换解决方案。我正在尝试反序列化如下所示的 JSON 结果:
"error":[],
"result":
{
"MANAEUR":[
[1619042400,"1.11200","1.13488","1.08341","1.10077","1.09896","58878.56534370",137],
[1619046000,"1.09767","1.12276","1.08490","1.11097","1.10456","25343.25910419",77],
],
"last":1619118000
}
我使用以下类:
public class ResponseBase
{
[JsonProperty(PropertyName = "error")]
public List<string> Error;
}
public class OHLCResponse : ResponseBase
{
[JsonProperty("result")]
public OHLCResult Result;
}
public class OHLCResult
{
[JsonProperty("pair_names")]
public Dictionary<string, OHLC[]> GetHistory;
[JsonProperty("last")]
public long Last;
}
....最后是它的胆量:
public class OHLC
{
public int Time;
public decimal Open;
public decimal High;
public decimal Low;
public decimal Close;
public decimal Vwap;
public decimal Volume;
public int Count;
}
我有一个标准的解串器类,它适用于我对同一 API 使用的所有其他调用,但我无法让这个调用工作。当我检索 OHLCResponse 对象时,我没有收到错误消息,并且始终填充“Result.Last”,但“Result.GetHistory”中的预期 OHLC 项数组始终为空/null。我知道数据已经成功返回,因为我可以看到从 WebRequest 返回的变量中的数据,然后我将其传递给反序列化器函数,所以我猜这些类的布局一定是错误的。
谁能看到我做错了什么?
非常感谢,戴夫
解决方案
您发布的对象不是有效的 JSON。缺少外部花括号。所以我假设它应该是这样的:
{
"error": [],
"result": {
"MANAEUR": [
[1619042400, "1.11200", "1.13488", "1.08341", "1.10077", "1.09896", "58878.56534370", 137],
[1619046000, "1.09767", "1.12276", "1.08490", "1.11097", "1.10456", "25343.25910419", 77],
],
"last": 1619118000
}
}
匿名反序列化
您可以做的第一种方法是使用匿名反序列化,这可能有点笨拙,因为您必须反序列化两次。
让我们从定义一些模型开始:
public sealed class OHLCModel
{
public long Time { get; set; }
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public decimal Vwap { get; set; }
public decimal Volume { get; set; }
public int Count { get; set; }
}
public sealed class ResultModel
{
[JsonIgnore]
public IEnumerable<OHLCModel> Manaeur { get; set; }
[JsonProperty("last")]
public long Last { get; set; }
}
public sealed class RootModel
{
[JsonProperty("error")]
public List<string> Error { get; set; }
[JsonProperty("result")]
public ResultModel Result { get; set; }
}
如您所见,Manaeur
当序列化发生时,我们忽略了对象。
为了使这个方法有效,我们这样做:
var json = System.IO.File.ReadAllText(@"c:\users\andy\desktop\test.json");
// First, just grab the object that has the mixed arrays.
// This creates a "template" of the format of the target object
var dto = JsonConvert.DeserializeAnonymousType(json, new
{
Result = new
{
Manaeur = new List<List<object>>()
}
});
// Next, deserialize the rest of it
var fullObject = JsonConvert.DeserializeObject<RootModel>(json);
// transfer the DTO using a Select statement
fullObject.Result.Manaeur = dto.Result.Manaeur.Select(x => new OHLCModel
{
Time = Convert.ToInt64(x[0]),
Open = Convert.ToDecimal(x[1]),
High = Convert.ToDecimal(x[2]),
Low = Convert.ToDecimal(x[3]),
Close = Convert.ToDecimal(x[4]),
Vwap = Convert.ToDecimal(x[5]),
Volume = Convert.ToDecimal(x[6]),
Count = Convert.ToInt32(x[7])
});
这不是最理想的解决方案,因为您在几个地方与模型紧密耦合。做到这一点的理想方法是自定义JsonSerializer
.
使用自定义 JsonConverter
我们要做的第一件事就是把你改成ResultModel
这样:
public sealed class ResultModel
{
[JsonConverter(typeof(ManaeurJsonConverter)), JsonProperty("MANAEUR")]
public IEnumerable<OHLCModel> Manaeur { get; set; }
[JsonProperty("last")]
public long Last { get; set; }
}
然后实现一个JsonConverter
:
public sealed class ManaeurJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => false; // this will never get called
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var lst = JArray.Load(reader).ToObject<List<List<object>>>();
return lst.Select(x => new OHLCModel
{
Time = Convert.ToInt64(x[0]),
Open = Convert.ToDecimal(x[1]),
High = Convert.ToDecimal(x[2]),
Low = Convert.ToDecimal(x[3]),
Close = Convert.ToDecimal(x[4]),
Vwap = Convert.ToDecimal(x[5]),
Volume = Convert.ToDecimal(x[6]),
Count = Convert.ToInt32(x[7])
});
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{ // we don't need to write
throw new NotImplementedException();
}
}
然后,您可以简单地这样称呼它:
var json = System.IO.File.ReadAllText(@"c:\users\andy\desktop\test.json");
var fullObject = JsonConvert.DeserializeObject<RootModel>(json);
推荐阅读
- javascript - $(element).position().top 返回错误值
- unit-testing - 解决在 H2 数据库中无法理解语句以进行单元测试的 flyway 迁移的最佳实践
- javascript - 如何使用 JavaScript 为每个问题创建一个计时器
- steam - Steam API:获取当前 UTC 日期时间
- javascript - 如何在 ReactJs 中上传图像作为输入字段?
- java - 在 Java 中使用 HttpUrlConnection 获取 421 代码
- swift - 如何将 try 与合并运算符一起使用?
- javascript - 防止 Edge 和 Chrome 在 autoform 上更改颜色
- java - 同时长按2个按钮的监听器
- c# - 从另一个 C# 程序启动 C# 程序