【问题标题】:JSON Can't be Deserialized to Object, Needs Array?JSON 不能反序列化为对象,需要数组吗?
【发布时间】:2012-06-23 05:36:13
【问题描述】:

我正在尝试获取传入的 JSON 项目并将它们绑定到列表框项目,但 Visual Studio 告诉我我需要做一个数组而不是对象?我从来没有这样做过……有人知道怎么做吗?

我的根对象:

public class RootObject
{
    public string url { get; set; }
    public string display { get; set; }
    public List<string> genetics { get; set; }
    public List<string> price { get; set; }
    public List<string> brandMaker { get; set; }
    public string form { get; set; }
    public string dosornos { get; set; }
    public string qty { get; set; }
    public string mfg { get; set; }
    public string mobURI { get; set; }
}

注意:Genetics、Price、BrandMaker 实际上只返回一个值,如下所示:

"genetics": [
    "typeophere"
],
"price": [
    "$1400"
],

JSON 文件/请求基本结果:

  [
{
    "url": "N/A",
    "display": "",
    "genetics": [
        "microogiz"
    ],
    "price": [
        "96.016"
    ],
    "brandMaker": [
        "Oshi Kunti Multikashi, Osaka, JP"
    ],
    "form": "tangent",
    "dosornos": "n/a",
    "qty": "88G",
    "mfg": "SelfMade Industries, USA Dist.",
    "mobURI": "n/a"
}

]

我的原始代码:

// Get JSON via WEB
string ProviderURI = goURI;
webClient webClient = new WebClient();
webClient.DownloadStringCompleted += new  
    DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(new Uri(ProviderURI));

void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    if (e.Error != null)
    {
        return;
    }

    var deserializedJSON = JsonConvert.DeserializeObject<RootObject>(e.Result);
    lstBoxResults.ItemsSource = deserializedJSON; // or deserializedJSON.url.ToString();
}

【问题讨论】:

  • 你能发布 goURI 返回的原始 JSON 吗?
  • 请发布原始 JSON 响应。只是一个提示,但开始使用适当的套管,例如为您的属性使用 Pascal 套管。局部变量的骆驼外壳......等等。
  • 我猜你会得到字符串作为回报......首先将该字符串解析为 json 然后反序列化它。
  • dbaseman 和 Christophe Geers 我刚刚添加了它。

标签: c# json windows-phone-7 windows-phone-7.1 windows-phone


【解决方案1】:

好的,您提到遗传学和价格是数组,但返回的 JSON 仅包含一项。 RootObject 的其余部分是简单的字符串属性。

因为您没有发布原始 JSON 示例。让我展示一个精简的版本,以保持简单和简短。

{
    "url": "http://www.stackoverflow.com",
    "display": "This is a test",
    "genetics": [
        "typeophere"
    ],
    "price": [
        "$1400"
    ],
    "form": "a form"
}

现在我们可以精简 RootObject 类类型。我为我的属性使用了 Pascal 大小写,并将它们归因于 JSON.NET 属性以协助反序列化/序列化。

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class RootObject
{
    [JsonProperty(PropertyName = "url")]
    public string Url { get; set; }

    [JsonProperty(PropertyName = "display")]
    public string Display { get; set; }

    [JsonProperty(PropertyName = "genetics")]
    public List<string> Genetics { get; set; }

    [JsonProperty(PropertyName = "price")]
    public List<string> Price { get; set; }

    [JsonProperty(PropertyName = "form")]
    public string Form { get; set; }
}

由于我不知道您调用的 Web 服务,我只是将此 JSON 存储在一个文本文件中。将其标记为嵌入式资源并从那里读取。

string json;
var resource = Application.GetResourceStream(new Uri("json.txt", UriKind.Relative));
using (var reader = new StreamReader(resource.Stream))
{
    json = reader.ReadToEnd();
}

只需将此部分替换为您的 WebClient 调用即可获取您的 JSON 数据。

现在我们可以将 JSON 反序列化为 RootObject 实例。

var rootObject = JsonConvert.DeserializeObject<RootObject>(json);

按广告宣传。现在您需要将它绑定到 ListBox 控件。如果将鼠标悬停在 ListBox 实例的 ItemSource 属性上,您会看到工具提示提到您可以将其绑定到集合。好吧,单个 rootObject 不是一个集合。不能直接绑定。

lstBoxResults.ItemsSource = rootObject;

这行不通。您不能将 RootObject 实例转换为 System.Collections.IEnumerable。这是 ItemsSource 所期望的。

轻松修复。让我们创建一个集合。

lstBoxResults.ItemsSource = new List<RootObject> { rootObject };

这是假设您的 JSON 数据只返回一个 rootObject。您的 ListBox 中只会出现一项。

现在让我们假设您的 JSON 数据返回一个 RootObjects 数组。例如一个名为“items”的数组,其中包含 RootItems 的集合。

{
    "items": [
    {
    "url": "http://www.stackoverflow.com",
    "display": "This is a test",
    "genetics": [ "typeophere" ],
    "price": [ "$1400" ],
    "form": "a form"        
    },
    {
    "url": "https://github.com/geersch",
    "display": "This is another test",
    "genetics": [ "typeophere" ],
    "price": [ "$2000" ],
    "form": "another form"
    }]
}

反序列化同样容易。使用 JSON.NET 获取 RootObjects 的集合。

var data = JObject.Parse(json)["items"];

现在反序列化为一个集合(IEnumerable)。

var rootObjects = JsonConvert.DeserializeObject<IEnumerable<RootObject>>(data.ToString());

由于您现在已经拥有一个 RootObject 集合,因此无需自己创建一个。可以直接绑定到ListBox。

lstBoxResults.ItemsSource = rootObjects;

您收到的 JSON 数据似乎无效。在解析它之前,请确保您对其进行了修改,以便您拥有一个有效的 JSON 对象。

例如:

json = json.Substring(json.IndexOf("[") + 1);
json = json.Substring(0, json.LastIndexOf("]"));
var rootObjects = JsonConvert.DeserializeObject<RootObject>(json);

【讨论】:

  • 首先,非常感谢您的帮助!我确实有一个问题......在我请求 JSON 文件并告诉它转到 DownloadStringCompleted 后,我运行:“var rootObject = JsonConvert.DeserializeObject(e.Result); pillResults.ItemsSource = new List { 根对象 };"甚至使用你的类,它错误说“无法将当前 JSON 数组(例如 [1,2,3])反序列化为类型 'HealthCenter.MainPage+RootObject',因为该类型需要 JSON 对象(例如 {"name":"value "}) 正确反序列化。将 JSON 更改为 JSON 对象(例如 {"name":"value"})更改为数组
  • 嗯,您在问题中显示的 JSON 响应无效。如果我尝试解析它,我会得到同样的异常。删除括号 [ ],您将拥有一个可以解析的有效 JSON 对象。虽然它只是一个 RootObject。
  • 您好 Christophe,很遗憾,我认为公司暂时不会让我更改它们,但我可能会提交一份副本。它适用于我们的 iOS 设备,但奇怪的 WP7 无法做到。再次感谢您的帮助!
  • 您收到 JSON 数据作为字符串。只需在使用 JSON.NET 库解析它之前更正它。并不是说你应该去修复提供它的网络服务。
【解决方案2】:

试试这个

RootObject rootObject;

if (json.startsWith("["))
{
  rootObject = JsonConvert.DeserializeObject<List<RootObject>>(json)[0];
}
else
{
  rootObject = JsonConvert.DeserializeObject<RootObject>(json);
}

【讨论】:

  • 这行得通,不幸的是不能在第一个 if/check 中将 rootObject 添加到列表框项目源中,但没关系。唯一的另一个问题是,如果我正在做某事,比如 brandMaker 并做 rootObject.brandMaker 我必须添加 .ToString();但不显示,它显示 System.Collections...无论哪种方式,都适用于某些项目,太棒了,谢谢!
猜你喜欢
  • 1970-01-01
  • 2016-01-30
  • 2020-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-18
  • 1970-01-01
  • 2021-10-29
相关资源
最近更新 更多