如何将JSON数组反序列化为类型安全的C#类示例

x6yk4ghg  于 2023-04-08  发布在  C#
关注(0)|答案(2)|浏览(110)

这个问题几乎与here相同
我试着把答案翻译成C#,但我不是JSONMaven,有点迷路了。
我正在尝试从Kraken OHLC端点反序列化此JSON响应。Example response, click here
请求会拉回这个JSON:

{
"error":[],

"result":
        {
            "XXBTZEUR":
                    [
                        [1679269500,"26401.1","26401.1","26211.6","26243.9","26307.1","8.92959425",311],
                        [1679270400,"26253.1","26324.7","26060.2","26242.9","26212.0","33.15872129",520],
                        [1679271300,"26250.1","26276.8","26216.8","26260.4","26259.0","3.63710383",183]
                    ],
                
            "last":1679915700

        }}

它是有效的JSON,但我不知道如何处理“last”字段,它似乎会抛出所有内容。
我以为我已经接近这些Class结构了,但无论如何,我的内部数组返回为null:

public class OHLCResponse
{
    [JsonProperty(PropertyName = "error")]
    public List<string> Error;

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

public class OHLC
{
    //[JsonProperty("ohlc_pairs")]
    public Dictionary<string, List<OHLCPair>> OHLCPairs { get; set; }

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

public class OHLCPair 
{
    [JsonProperty("time")]
    public int UnixDateStamp { get; set; }
    [JsonProperty("open")]
    public string Open { get; set; }
    [JsonProperty("high")]
    public string High { get; set; }
    [JsonProperty("low")]
    public string Low { get; set; }
    [JsonProperty("close")]
    public string Close { get; set; }
    [JsonProperty("vwap")]                  //volume weighted average price
    public string VWAP { get; set; }
    [JsonProperty("volume")]
    public string Volume { get; set; }
    [JsonProperty("count")]
    public string Count { get; set; }
}

我只是用一个标准库来调用它,这个库很高兴地将大多数其他对象处理成API中的类型安全类:

OHLCResponse cOHLCResponse = _CKraken.GetPublicWebResponse<OHLCResponse>("OHLC", param);

...实现:

result = (T)JsonConvert.DeserializeObject<T>(json);

结果,无论我如何尝试改变我的类型Classes总是一个空数组,因为我认为它无法处理“last”字段:

有人能给我指出正确的方向吗?很遗憾,我无法翻译上一个问题中的自定义反序列化器。提前感谢你,Dave。

ut6juiuv

ut6juiuv1#

  • 真是个很有挑战性的问题 *

我认为可以通过为OHLCOHLCPair类实现自定义JSON转换器来实现这一点。
1.使用相应属性的JsonConverter属性注册JsonConverter

public class OHLCResponse
{   
    [JsonProperty(PropertyName = "error")]
    public List<string> Error;

    [JsonProperty(PropertyName = "result")]
    [JsonConverter(typeof(OHLCConverter))]
    public OHLC Result { get; set; }
}

public class OHLC
{
    public OHLC() { }
        
    [JsonProperty("ohlc_pairs")]
    public Dictionary<string, List<OHLCPair>> OHLCPairs { get; set; }

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

[JsonConverter(typeof(OHLCPairConverter))]
public class OHLCPair 
{
    public OHLCPair() { }

    
    [JsonProperty("time")]
    public long UnixDateStamp { get; set; }
    [JsonProperty("open")]
    public string Open { get; set; }
    [JsonProperty("high")]
    public string High { get; set; }
    [JsonProperty("low")]
    public string Low { get; set; }
    [JsonProperty("close")]
    public string Close { get; set; }
    [JsonProperty("vwap")]                  //volume weighted average price
    public string VWAP { get; set; }
    [JsonProperty("volume")]
    public string Volume { get; set; }
    [JsonProperty("count")]
    public int Count { get; set; }
}
  • OHLCPairConverter中,它旨在将last字段以外的键值对转换为Dictionary<string, List<OHLCPair>>,并将其分配给OHLCPairs属性。
  • OHLCPairConverter中,它旨在将具有多个值和类型的数组(JArray)转换为OHLCPair示例。
public class OHLCConverter : JsonConverter<OHLC>
{
    public override void WriteJson(JsonWriter writer, OHLC value, JsonSerializer serializer)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            Converters = serializer.Converters.Where(s => !(s is OHLCConverter)).ToList(),
            DateFormatHandling = serializer.DateFormatHandling,
            MissingMemberHandling = serializer.MissingMemberHandling,
            NullValueHandling = serializer.NullValueHandling,
            Formatting = serializer.Formatting
        };
        var localSerializer = JsonSerializer.Create(settings);
        
        writer.WriteStartObject();
        
        foreach (PropertyInfo propInfo in typeof(OHLC).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty))
        {
            var jsonPropAttr = propInfo.GetCustomAttributes<JsonPropertyAttribute>()
                .FirstOrDefault();
            var propName = jsonPropAttr != null
                ? jsonPropAttr.PropertyName
                : propInfo.Name;
                
            writer.WritePropertyName(propName);
            
            if (propInfo.Name == "OHLCPairs")
            {
                var jObject = JObject.FromObject(propInfo.GetValue(value), localSerializer);
                jObject.WriteTo(writer);
            }
            else
            {
                writer.WriteValue(propInfo.GetValue(value));
            }
        }
        
        writer.WriteEndObject();
    }

    public override OHLC ReadJson(JsonReader reader, Type objectType, OHLC existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        JObject obj = JObject.FromObject(token);
        Dictionary<string, List<OHLCPair>> ohlcPairs = null;
        
        if (token.Type != JTokenType.Null)
        {
                ohlcPairs = obj.ToObject<Dictionary<string, object>>()
                        .Where(x => x.Key != "last")
                        .ToDictionary(x => x.Key, 
                                      x => JArray.FromObject(x.Value)
                                        .Children<JArray>()
                                        .Select(x => JsonConvert.DeserializeObject<OHLCPair>(x.ToString(), new JsonSerializerSettings
                                                                   {
                                                                        Converters = new List<JsonConverter> { new OHLCPairConverter() }   
                                                                   }))
                                        .ToList());
        }
    
        return new OHLC
        {
            OHLCPairs = ohlcPairs,
            Last = obj["last"].ToObject<int>()
        };
    }
}

public class OHLCPairConverter : JsonConverter<OHLCPair>
{
    public override void WriteJson(JsonWriter writer, OHLCPair value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        
        foreach (PropertyInfo propInfo in typeof(OHLCPair).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty))
        {
            var jsonPropAttr = propInfo.GetCustomAttributes<JsonPropertyAttribute>()
                .FirstOrDefault();
            var propName = jsonPropAttr != null
                ? jsonPropAttr.PropertyName
                : propInfo.Name;
                
            writer.WritePropertyName(propName);
            writer.WriteValue(propInfo.GetValue(value));
        }
                
        writer.WriteEndObject();
    }

    public override OHLCPair ReadJson(JsonReader reader, Type objectType, OHLCPair existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        JArray jArray = JArray.FromObject(token);
        
        return new OHLCPair
        {
            UnixDateStamp = jArray[0].ToObject<int>(),
            Open = jArray[1].ToObject<string>(),
            High = jArray[2].ToObject<string>(),
            Low = jArray[3].ToObject<string>(),
            Close = jArray[4].ToObject<string>(),
            VWAP = jArray[5].ToObject<string>(),
            Volume = jArray[6].ToObject<string>(),
            Count = jArray[7].ToObject<int>()
        };
    }
}

无论如何,对于WriteJson方法,您可以通过决定格式,属性及其要打印的值来实现编写JSON(序列化),而不需要 * System.Reflection *。我的方法似乎过于复杂。

4jb9z9bj

4jb9z9bj2#

你只需要一个简单的转换器

using Newtonsoft.Json;

OHLCResponse oHLCResponse = JsonConvert.DeserializeObject<OHLCResponse>(json, new OHLCConverter());
    
public class OHLCConverter : JsonConverter<OHLCResponse>
{
    public override OHLCResponse ReadJson(JsonReader reader, Type objectType, OHLCResponse existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jObj = JObject.Load(reader);
        var props = ((JObject)jObj["result"]).Properties().ToArray();
        var dict = new Dictionary<string, List<OHLCPair>>();

        for (int i = 0; i < props.Length; i++)
        {
            var prop = props[i];
            if (prop.Value.Type != JTokenType.Array) continue;

            var arr = new JArray( prop.Value.Select(v => new JObject(
                     v.Select((x, index) => new JProperty(index.ToString(),x)))) );
                                
            dict.Add(prop.Name, arr.ToObject<List<OHLCPair>>());
            prop.Remove();
        }
        OHLCResponse oHLCResponse = jObj.ToObject<OHLCResponse>();
        oHLCResponse.Result.OHLCPairs = dict;
        return oHLCResponse;
    }

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

并更改OHLCPair类的JsonProperty属性

public class OHLCPair
{
    [JsonProperty("0")]
    public int UnixDateStamp { get; set; }
    [JsonProperty("1")]
    public string Open { get; set; }
    [JsonProperty("2")]
    public string High { get; set; }
    [JsonProperty("3")]
    public string Low { get; set; }
    [JsonProperty("4")]
    public string Close { get; set; }
    [JsonProperty("5")]
    public string VWAP { get; set; }
    [JsonProperty("6")]
    public string Volume { get; set; }
    [JsonProperty("7")]
    public int Count { get; set; }
}

相关问题