【问题标题】:How to parse a json object array containing mixed primitive types using DataContractJsonSerializer?如何使用 DataContractJsonSerializer 解析包含混合原始类型的 json 对象数组?
【发布时间】:2017-02-22 14:16:29
【问题描述】:

如何在 C# 中使用 DataContractJsonSerializer 解析下面的 JSON 对象?

我需要定义一个类来保存以下 JSON 数据,其中包括混合类型(字符串和整数)的基元数组的数组:

Body:
    {
      "status": "failure",
      "staticdata": [
        [
          "2013-06-01",
          123
        ],
        [
          "2013-06-02",
          234
        ],
        [
          "2013-06-03",
          345
        ],    
        ...
      ]
    }

我尝试了以下答案并尝试通读DataContractJsonSerializer

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (object[] sd in jsonResponse.staticdata)
{
    foreach (object o in sd)
    {
        //Value val = v as Value;
        Value val = (Value)Convert.ChangeType(o, typeof(Value));
            log.Info("date: " + val.date);
            log.Info("crashCount: " + val.longValue);
   }
} 

但是在从对象到值的转换类型中崩溃了,我在这里遗漏了什么吗?

值低于类:

[DataContract]
public class Value
{
    [DataMember(Name = "date")]
    public string date { get; set; }

    [DataMember(Name = "longValue")]
    public long longValue{ get; set; }
}

修改后的代码读取Values(IgnoreDataMember Values),然后可以读取如下:这是正确的方法吗?

object objResponse = jsonSerializer.ReadObject(response);

RootObject jsonResponse = objResponse as RootOject;

foreach (Value in jsonResponse.Values)
{
            log.Info("date: " + val.date);
            log.Info("longValue: " + val.longValue);
} 

【问题讨论】:

标签: c# arrays json datacontractjsonserializer


【解决方案1】:

如果你只是想反序列化你的 JSON,你可以使用像 http://json2csharp.com/Paste JSON As Classes 这样的代码生成工具并获得以下数据模型,它与 DataContractJsonSerializer 完美配合:

public class RootObject
{
    public string status { get; set; }
    public List<List<object>> staticdata { get; set; }
}

object 有效,因为DataContractJsonSerializer 自动识别和序列化已知的原始类型,例如stringint

但您可能想要将您的 "staticdata" 数组反序列化为如下类的列表:

public class Value
{
    public string Date { get; set; }
    public int IntValue { get; set; }
}

如果是这样,您可以使用RootObject 类型中的代理属性进行转换:

[DataContract]
public class RootObject
{
    [DataMember]
    public string status { get; set; }

    [DataMember]
    object[][] staticdata
    {
        get
        {
            if (Values == null)
                return null;
            return Values.Select(v => new object[] { v.Date, v.IntValue }).ToArray();
        }
        set
        {
            if (value == null)
                return;
            Values = value.Select(a => new Value 
                { 
                    Date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
                    IntValue = a.Length < 2 ? 0 : (int)Convert.ChangeType(a[1], typeof(int), CultureInfo.InvariantCulture) 
                }
                ).ToList();
        }
    }

    [IgnoreDataMember]
    public List<Value> Values { get; set; }
}

更新

在您提出的更新问题中,但是在从对象到值的转换类型崩溃了,我在这里遗漏了什么吗?

您的问题是您尝试使用Convert.ChangeType()object 转换为Value,但此方法仅适用于可以相互转换的原始 数据类型字符串。来自docs

ChangeType 是一种通用的转换方法,它将值指定的对象转换为conversionType。 value 参数可以是任何类型的对象,conversionType 也可以是表示任何基本类型或自定义类型的 Type 对象。 要使转换成功,value 必须实现IConvertible 接口,因为该方法简单地包装了对适当IConvertible 方法的调用。

由于您的Value 类型没有实现此接口,因此转换失败。

相反,您应该在嵌套数组中的各个条目上使用Convert.ChangeType。鉴于您的 RootObject 看起来像:

public class RootObject
{
    public string status { get; set; }
    public object [][] staticdata { get; set; }
}

你应该这样做:

using System.Linq;

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));
var jsonResponse = (RootObject)jsonSerializer.ReadObject(response);

var query = jsonResponse.staticdata
    // For each object [] array in the outer array
    .Select(a => new Value
        {
             // Convert the inner array to a Value, using the first element for the date and the second element for the longValueand the second element for the longValue
            date = a.Length < 1 ? null : (string)Convert.ChangeType(a[0], typeof(string), CultureInfo.InvariantCulture),
            longValue = a.Length < 2 ? 0 : (long)Convert.ChangeType(a[1], typeof(long), CultureInfo.InvariantCulture)
        });

foreach (var val in query)
{
    log.Info("date: " + val.date);
    log.Info("crashCount: " + val.longValue);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2020-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    • 2011-06-14
    相关资源
    最近更新 更多