简体   繁体   English

如何在C#中反序列化JSON数组

[英]How to deserialize json array in c#

I am trying to deserialize the following JSON file: http://komunikaty.tvp.pl/komunikatyxml/malopolskie/wszystkie/0?_format=json 我正在尝试反序列化以下JSON文件: http : //komunikaty.tvp.pl/komunikatyxml/malopolskie/wszystkie/0?_format=json

My c# code: 我的C#代码:

MemoryStream stream1 = new MemoryStream();
StreamWriter writer = new StreamWriter(stream1);
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ApiRegionalne));
writer.Write(json);
writer.Flush();
stream1.Position = 0;
dane = (ApiRegionalne)ser.ReadObject(stream1);

And my classes: 我的课程:

[DataContract]
public class newses
{
    public int id;
    public string title;
    public bool shortcut;
    public string content;
    public bool rso_alarm;
    public string rso_icon;
    public string longitude;
    public string latitude;
    public int water_level_value;
    public int water_level_warning_status_value;
    public int water_level_alarm_status_value;
    public int water_level_trend;
    public string river_name;
    public string location_name;
    public string type;
}

[DataContract]
public class ApiRegionalne
{
    [DataMember(Name = "newses")]
    public newses[] newses;
}

The JSON deserializer doesn't throw any exceptions, but my data is nevertheless null. JSON反序列化器不会引发任何异常,但是我的数据仍然为null。

What am I doing wrong? 我究竟做错了什么?

You need to mark all of the public fields of class newses as being part of the contract: 您需要将所有类newses的公共字段标记为合同的一部分:

[DataContract]
public class newses
{
    [DataMember(Name = "id")] //This is what you need to add
    public int id;

    //Do the same for all other fields        
}

Your basic problem is that the data contract serializers (both DataContractSerializer and DataContractJsonSerializer ) are opt-in . 您的基本问题是数据合同序列化程序( DataContractSerializerDataContractJsonSerializer )都已选择加入 If you mark a type with [DataContract] you must also mark the members to be serialized with [DataMember] , as explained in Using Data Contracts : 如果使用[DataContract]标记类型,则还必须使用[DataMember]标记要序列化的成员,如使用数据合约中所述

You can also explicitly create a data contract by using DataContractAttribute and DataMemberAttribute attributes. 您还可以使用DataContractAttributeDataMemberAttribute属性显式创建数据协定。 This is normally done by applying the DataContractAttribute attribute to the type. 通常通过将DataContractAttribute属性应用于该类型来完成此操作。 This attribute can be applied to classes, structures, and enumerations. 此属性可以应用于类,结构和枚举。 The DataMemberAttribute attribute must then be applied to each member of the data contract type to indicate that it is a data member, that is, it should be serialized. 然后必须将DataMemberAttribute属性应用于数据协定类型的每个成员,以表明它是数据成员,即应进行序列化。

You have not applied [DataMember] to any of the members of your newses type, so none if its members are deserialized. 您尚未将[DataMember]应用于newses类型的任何成员,因此,如果其成员已反序列化,则不会应用。

A second problem is that you have declared water_level_trend as an int , but it appears as an empty string in the JSON: 第二个问题是您已将water_level_trend声明为int ,但在JSON中却显示为空字符串:

     "water_level_trend":"",

An empty string cannot be bound to an integer; 空字符串不能绑定到整数。 if you try, DataContractJsonSerializer will throw the following exception: 如果尝试, DataContractJsonSerializer将引发以下异常:

There was an error deserializing the object of type ApiRegionalne. 反序列化ApiRegionalne类型的对象时出错。 The value '' cannot be parsed as the type 'Int32'. 值''不能解析为类型'Int32'。

Since you appear to want to explicitly mark your types with data contract attributes, you can use the site https://jsonutils.com/ to auto-generate your types for you with the desired attributes applied. 由于您似乎想用数据协定属性显式标记您的类型,因此可以使用站点https://jsonutils.com/为您自动应用所需的属性来生成类型。 You can also choose to automatically camel-case your property and type names, bringing then into conformance with the recommended .Net style: 您还可以选择自动使用驼峰式大小写属性和类型名称,然后使其与建议的.Net样式保持一致:

[DataContract]
public class Pagination
{
    [DataMember(Name = "totalitems")]
    public int Totalitems { get; set; }

    [DataMember(Name = "itemsperpage")]
    public int Itemsperpage { get; set; }
}

[DataContract]
public class Six // Fixed name from 6
{
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }

    [DataMember(Name = "city")]
    public string City { get; set; }

    [DataMember(Name = "slug_name")]
    public string SlugName { get; set; }
}

[DataContract]
public class Provinces
{
    [DataMember(Name = "6")]
    public Six Six { get; set; }
}

[DataContract]
public class News
{
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "title")]
    public string Title { get; set; }

    [DataMember(Name = "shortcut")]
    public string Shortcut { get; set; }

    [DataMember(Name = "content")]
    public string Content { get; set; } // Fixed type from object

    [DataMember(Name = "rso_alarm")]
    public string RsoAlarm { get; set; }

    [DataMember(Name = "rso_icon")]
    public string RsoIcon { get; set; } // Fixed type from object

    [DataMember(Name = "valid_from")]
    public string ValidFrom { get; set; }

    [DataMember(Name = "0")]
    public string Zero { get; set; }  // Fixed name from 0

    [DataMember(Name = "valid_to")]
    public string ValidTo { get; set; }

    [DataMember(Name = "1")]
    public string One { get; set; } // Fixed name from 1

#if false
    // Removed since the correct type is unknown.
    [DataMember(Name = "repetition")]
    public object Repetition { get; set; }
#endif

    [DataMember(Name = "longitude")]
    public string Longitude { get; set; }

    [DataMember(Name = "latitude")]
    public string Latitude { get; set; }

    [DataMember(Name = "water_level_value")]
    public int WaterLevelValue { get; set; } // Fixed type to int

    [DataMember(Name = "water_level_warning_status_value")]
    public int WaterLevelWarningStatusValue { get; set; } // Fixed type to int

    [DataMember(Name = "water_level_alarm_status_value")]
    public int WaterLevelAlarmStatusValue { get; set; } // Fixed type to int

    [DataMember(Name = "water_level_trend")]
    public string WaterLevelTrend { get; set; } // This must remain a string since it appears as a non-numeric empty string in the JSON: "".

    [DataMember(Name = "river_name")]
    public string RiverName { get; set; }

    [DataMember(Name = "location_name")]
    public string LocationName { get; set; }

    [DataMember(Name = "created_at")]
    public string CreatedAt { get; set; }

    [DataMember(Name = "2")]
    public string Two { get; set; } // // Fixed name from 2

    [DataMember(Name = "updated_at")]
    public string UpdatedAt { get; set; }

    [DataMember(Name = "3")]
    public string Three { get; set; } // Fixed name from 3

    [DataMember(Name = "type")]
    public string Type { get; set; }

    [DataMember(Name = "provinces")]
    public Provinces Provinces { get; set; }
}

[DataContract]
public class ApiRegionalne
{
    [DataMember(Name = "pagination")]
    public Pagination Pagination { get; set; }

    [DataMember(Name = "newses")]
    public IList<News> Newses { get; set; }
}

Note it was necessary to make some manual fixes to the auto-generated types such as renaming numeric properties to some appropriate non-numeric name, eg 1 to One . 请注意,有必要对自动生成的类型进行一些手动修复,例如将数字属性重命名为一些适当的非数字名称,例如1One In addition it was necessary to change the types of some properties that were null in the JSON from object to something more appropriate such as string . 另外,有必要将JSON中为null的某些属性的类型从object更改为更合适的属性,例如string The manual changes are commented above. 上面已评论了手动更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM