簡體   English   中英

將 JSON 反序列化為對象時出錯

[英]Error when deserializing JSON to Object

我需要轉換從 REST API 獲取的 JSON 數據,並將它們轉換為 CSV 以進行一些分析。 問題是 JSON 數據不一定遵循相同的內容,所以我無法定義映射類型。 這已經成為一個挑戰,占用了我太多的時間。 我已經創建了一些代碼,但當然它不起作用,因為它在這一行拋出異常

var data = JsonConvert.DeserializeObject<List<object>>(jsonData);

錯誤是:

附加信息:無法將當前 JSON 對象(例如 {"name":"value"})反序列化為類型“System.Collections.Generic.List`1[System.Object]”,因為該類型需要一個 JSON 數組(例如 [1 ,2,3]) 正確反序列化。

要修復此錯誤,請將 JSON 更改為 JSON 數組(例如 [1,2,3])或更改反序列化類型,使其成為普通的 .NET 類型(例如,不是像整數這樣的原始類型,也不是像這樣的集合類型一個數組或列表),可以從 JSON 對象反序列化。 JsonObjectAttribute 也可以添加到類型以強制它從 JSON 對象反序列化。

路徑“數據”,第 2 行,位置 10。

請讓我知道我能做些什么來實現這一目標。

一個數據樣本是這樣的,數據的字段經常變化,例如第二天可以添加一個新字段,所以我沒有自由創建一個.Net類來映射數據。

{
  "data": [
    {
      "ID": "5367ab140026875f70677ab277501bfa",
      "name": "Happiness Initiatives - Flow of Communication/Process & Efficiency",
      "objCode": "PROJ",
      "percentComplete": 100.0,
      "plannedCompletionDate": "2014-08-22T17:00:00:000-0400",
      "plannedStartDate": "2014-05-05T09:00:00:000-0400",
      "priority": 1,
      "projectedCompletionDate": "2014-12-05T08:10:21:555-0500",
      "status": "CPL"
    },
    {
      "ID": "555f452900c8b845238716dd033cf71b",
      "name": "UX Personalization Think Tank and Product Strategy",
      "objCode": "PROJ",
      "percentComplete": 0.0,
      "plannedCompletionDate": "2015-12-01T09:00:00:000-0500",
      "plannedStartDate": "2015-05-22T09:00:00:000-0400",
      "priority": 1,
      "projectedCompletionDate": "2016-01-04T09:00:00:000-0500",
      "status": "APR"
    },
    {
      "ID": "528b92020051ab208aef09a4740b1fe9",
      "name": "SCL Health System - full Sitecore implementation (Task groups with SOW totals in Planned hours - do not bill time here)",
      "objCode": "PROJ",
      "percentComplete": 100.0,
      "plannedCompletionDate": "2016-04-08T17:00:00:000-0400",
      "plannedStartDate": "2013-11-04T09:00:00:000-0500",
      "priority": 1,
      "projectedCompletionDate": "2013-12-12T22:30:00:000-0500",
      "status": "CPL"
    }
 ]
}



namespace BusinessLogic
{
    public class JsonToCsv
    {

       public string ToCsv(string jsonData, string datasetName)
       {
          var data = JsonConvert.DeserializeObject<List<object>>(jsonData);
          DataTable table = ToDataTable(data); 
          StringBuilder result = new StringBuilder();

            for (int i = 0; i < table.Columns.Count; i++)
            {
                result.Append(table.Columns[i].ColumnName);
                result.Append(i == table.Columns.Count - 1 ? "\n" : ",");
            }

            foreach (DataRow row in table.Rows)
            {
                for (int i = 0; i < table.Columns.Count; i++)
                {
                    result.Append(row[i].ToString());
                    result.Append(i == table.Columns.Count - 1 ? "\n" : ",");
                }
            }

            return result.ToString().TrimEnd(new char[] {'\r', '\n'});

        }

        private DataTable ToDataTable<T>( IList<T> data )
            {
            PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
            DataTable table = new DataTable();
            for (int i = 0 ; i < props.Count ; i++)
                {
                PropertyDescriptor prop = props[i];
                table.Columns.Add(prop.Name, prop.PropertyType);
                }

            object[] values = new object[props.Count];
            foreach (T item in data)
                {
                for (int i = 0 ; i < values.Length ; i++)
                    {
                    values[i] = props[i].GetValue(item);
                    }

                table.Rows.Add(values);
                }

            return table;
            }


        }
}

這里真正的問題是您正在嘗試反序列化為List<object>但您的 JSON 實際上表示包含data屬性的單個對象,然后包含一個對象列表。 這就是您收到此錯誤的原因。 Json.Net 無法將單個對象反序列化為列表。 我認為您真正想要做的是定義一個容器類,如下所示:

class Root
{
    public List<Dictionary<string, object>> Data { get; set;}
}

然后像這樣反序列化:

var data = JsonConvert.DeserializeObject<Root>(jsonData).Data;

然后您將得到一個字典列表,其中每個字典代表 JSON 數組中的一個項目。 字典鍵值對是每個項目中的動態值。 然后,您可以像使用任何其他詞典一樣使用它們。 例如,這是轉儲所有數據的方法:

foreach (var dict in data)
{
    foreach (var kvp in dict)
    {
        Console.WriteLine(kvp.Key + ": " + kvp.Value);
    }
    Console.WriteLine();
}

小提琴: https ://dotnetfiddle.net/6UaKhJ

您正在尋找的是dynamic類型。 雖然不相關,但這個答案包含了很多關於如何迭代對象上不斷變化的屬性的信息。

您將需要添加一些額外的工作來弄清楚當您的結果是一個數組而不是單個對象時如何處理您的結果,正如您的錯誤向我們展示的那樣。 但是,這對您來說是良好的開端。

基本上, dynamic對象是一個字典,很像 JSON 對象在 JavaScript 中的處理方式。 您只需遍歷主對象中的每個 KeyValuePair 對象並檢查它們的屬性。

var data = JsonConvert.DeserializeObject<dynamic>(jsonData);
var rows = new List<string>();

// Go through the overall object, and get each item in 
// the array, or property in a single object.
foreach (KeyValuePair<string, object> item in data)
{
    dynamic obj = item.Value;
    var row = "";

    // Perhaps add a check here to see if there are more
    // properties (if it is an item in an array). If not
    // then you are working with a single object, and each
    // item is a property itself.
    foreach (KeyValuePair<string, object> prop in obj)
    {
        // Very dummy way to demo adding to a CSV
        string += prop.Value.ToString() + ",";
    }

    rows.Add(string);
}

這遠非一個完整的示例,但我們沒有足夠的信息繼續幫助您完成您正在嘗試做的事情。

您正在嘗試反序列化為一個列表,但您的 JSON 實際上表示一個包含包含對象列表的數據屬性的對象。 這就是您收到此錯誤的原因。 Json.Net 無法將單個對象反序列化為列表。

請試試這個:創建一個包含數據類型 Object 的單個屬性的類,並將此類傳遞給反序列化。

class Parent
{
    public object Data { get; set;}
}

然后像這樣反序列化:

var output = JsonConvert.DeserializeObject<Parent>(jsonData);

嘗試使用此類而不是 Object

public class Datum
{
    public string ID { get; set; }
    public string name { get; set; }
    public string objCode { get; set; }
    public double percentComplete { get; set; }
    public string plannedCompletionDate { get; set; }
    public string plannedStartDate { get; set; }
    public int priority { get; set; }
    public string projectedCompletionDate { get; set; }
    public string status { get; set; }
}

public class RootObject
{
    public List<Datum> data { get; set; }
}

更改為:

var data = JsonConvert.DeserializeObject<RootObject>(jsonData);

如果您的數據是動態的,請嘗試使用動態列表:

using System.Web.Script.Serialization;

JavaScriptSerializer jss = new JavaScriptSerializer();
var d=jss.Deserialize<dynamic>(str);

由於您正在嘗試將對象類型反序列化為列表類型,因此它不會直接反序列化。

你可以這樣做:

var data = JsonConvert.DeserializeObject<ObjectDataList>(jsonData);
var rows = new List<DeserializedData>();

foreach (dynamic item in data)
{
    var newData = new DeserializedData();
    foreach (dynamic prop in item)
    {
         var row = new KeyValuePair<string, string>
         (prop.Name.ToString(), prop.Value.ToString());
         newData.Add(row);
    }
    rows.Add(newData);
}

這是新課程

//class for key value type data

class DeserializedData
{
    List<KeyValuePair<string, string>> NewData = 
    new List<KeyValuePair<string, string>>();

    internal void Add(KeyValuePair<string, string> row)
    {
        NewData.Add(row);
    }
}


[DataContract]
class ObjectDataList
{
    [DataMember(Name ="data")]
    List<object> Data { get; set; }
    public IEnumerator<object> GetEnumerator()
    {
        foreach (var d in Data)
        {
            yield return d;
        }
    }
}

據我所知,更新版本的 Newtonsoft 現在實際上可以做到這一點,不需要額外的工作。

然而,我正在使用二進制版本,這仍然存在問題 - 我進行了一個測試,您可以在其中配置使用二進制或 json,並且 json 版本工作得很好,但二進制抱怨沒有獲得數組類型。

為此,我開始使用 BsonDataReader,並查看了它的屬性和方法,以了解如何最好地查看內容,你瞧,它有一個名為:

reader.ReadRootValueAsArray 

將其設置為“真”就可以了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM