-1

我在这里有一个与这个问题非常相似的问题,除了我的应用程序是用 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 返回的变量中的数据,然后我将其传递给反序列化器函数,所以我猜这些类的布局一定是错误的。

谁能看到我做错了什么?

非常感谢,戴夫

4

2 回答 2

1

您发布的对象不是有效的 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);
于 2021-04-23T01:21:40.533 回答
1

您的 JSON 无效,我必须对其进行修改以使其成为有效的 JSON ( https://jsonformatter.org/ )。我在第二个内部数组条目之后添加了根括号并删除了逗号分隔符。

有效的 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
    }
}

更新 JSON 后,我使用 Visual Studio 的“选择性粘贴”从 JSON 生成 C# 对象。创建了以下类。

public class RootObject
{
    [JsonProperty("error")]
    public object[] Error { get; set; }

    [JsonProperty("result")]
    public Result Result { get; set; }
}

public class Result
{
    [JsonProperty("MANAEUR")]
    public object[][] Manaeur { get; set; }

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

使用上面的 JSON 和类,我使用以下内容来反序列化 JSON。

string 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}}";
var obj = JsonConvert.DeserializeObject<RootObject>(json);

编辑:处理MANAEUR键标签可能不同的属性。

创建一个 JsonConverter...

public class ManaeurConverter : JsonConverter
{
    private Dictionary<string, string> propertyMappings { get; set; }
       
    public ManaeurConverter()
    {
        this.propertyMappings = new Dictionary<string, string>
        {
            {"NOTMANAEUR","MANAEUR"}
        };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        object instance = Activator.CreateInstance(objectType);
        var props = objectType.GetTypeInfo().DeclaredProperties.ToList();

        JObject jo = JObject.Load(reader);
        foreach (JProperty jp in jo.Properties())
        {
            if (!propertyMappings.TryGetValue(jp.Name, out var name))
                name = jp.Name;

            PropertyInfo prop = props.FirstOrDefault(pi =>
                    pi.CanWrite && pi.GetCustomAttribute<JsonPropertyAttribute>().PropertyName == name);

        prop?.SetValue(instance, jp.Value.ToObject(prop.PropertyType, serializer));
        }
        return instance;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.GetTypeInfo().IsClass;
    }

    public override bool CanWrite => false;
}

...将JsonConverter属性添加到类...

[JsonConverter(typeof(ManaeurConverter))]
public class Result
{
    [JsonProperty("MANAEUR")]
    public object[][] Manaeur { get; set; }

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

...并像这样解析...

string json_Manaeur = "{\"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}}";
string json_Not_Manaeur = "{\"error\":[],\"result\":{\"NOTMANAEUR\":[[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}}";
            
var objManaeur = JsonConvert.DeserializeObject<RootObject>(json_Manaeur);
var objNotManaeur = JsonConvert.DeserializeObject<RootObject>(json_Not_Manaeur);
于 2021-04-23T00:50:37.803 回答