【问题标题】:Deserializing a JSON array to a ObservableCollection将 JSON 数组反序列化为 ObservableCollection
【发布时间】:2013-05-11 19:28:16
【问题描述】:

我正在使用 RestSharp 与远程服务器进行通信。我收到一个 JSON 序列化字符串,我可以将其反序列化为 c# 对象。我还能够将 json 数组反序列化为 List。但是,我希望在 WPF 绑定中使用这些对象,因此为了方便起见,我需要将它们放在 ObservableCollection 中。但是,如果我尝试将属性从 List 更改为 ObservableCollection(或 IList、ICollection 或 Collection),我会在反序列化时遇到异常。

Unable to cast object of type 'RestSharp.JsonArray' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]

底层代码确实没啥特别的,不过这里还是有的:

private ObservableCollection<StationDto> stations;

[JsonProperty(PropertyName = "stations")]
public ObservableCollection<StationDto> Stations
{
    get { return this.stations; }
    set
    {
        this.stations = value;
        RaisePropertyChanged(() => Stations);
    }
}

我知道接口不起作用,因为 Json.net 需要一个具体的类来序列化。

我已经进行了大量的谷歌搜索,但我还没有看到解决方案。是否有一种模式常用于用于 json/rest 服务的手工代理?

【问题讨论】:

    标签: c# .net-4.0 json.net restsharp


    【解决方案1】:

    查看source code for RestSharp,它似乎使用自己的内部 JSON 反序列化器(称为 SimpleJson),而不是使用 Json.Net。 RestSharp documentation on deserialization 确认反序列化器仅支持 List&lt;T&gt; 和 Dictionary&lt;T1,T2&gt; 集合类型。另一方面,Json.Net 更加健壮,可以处理反序列化为 ObservableCollections。我用这篇文章末尾的代码试了一下,没有发现任何问题。考虑到这一点,我建议将 Json.Net 添加到您的解决方案中,并使用它来反序列化 REST API 调用的结果,而不是依赖 RestSharp 的内部反序列化器。有几种方法可以做到这一点:

    1. 您可以在 RestClient 上调用 Execute&lt;T&gt;(),而不是调用 Execute()。 Execute() 返回一个 IRestResponse,它有一个 Content 属性,其中包含从请求返回的原始 JSON 字符串。您可以将此字符串传递给 Json.Net 的 JsonConvert.DeserializeObject&lt;T&gt;() 方法。

    2. 创建一个实现 RestSharp 的IDeserializer 接口的类。让这个类简单地交给 Json.Net 来完成反序列化 JSON 的实际工作。然后,您可以通过在 RestClient 类上调用 AddHandler() 来告诉 RestSharp 使用这个自定义反序列化器而不是它自己的。根据文档,您以这种方式添加的处理程序将替换相同内容类型的现有处理程序。然后,您可以像现在一样继续使用RestClient,但它现在应该可以与ObservableCollections 一起使用。

    这是我用来测试 Json.Net 将反序列化为 ObservableCollection 的代码:

    class Program
    {
        static void Main(string[] args)
        {
            string json = @"{""stations"":[{""Name"":""WXRT""},{""Name"":""WGN""}]}";
    
            Foo foo = JsonConvert.DeserializeObject<Foo>(json);
    
            foreach (StationDto dto in foo.Stations)
            {
                Console.WriteLine(dto.Name);
            }
        }
    }
    
    class StationDto
    {
        public string Name { get; set; }
    }
    
    class Foo
    {
        private ObservableCollection<StationDto> stations;
    
        [JsonProperty(PropertyName = "stations")]
        public ObservableCollection<StationDto> Stations
        {
            get { return this.stations; }
            set 
            { 
                this.stations = value;
                RaisePropertyChanged(() => Stations);
            }
        }
    
        private void RaisePropertyChanged(Func<ObservableCollection<StationDto>> coll)
        {
        }
    }
    

    【讨论】:

    • 感谢您的建议,但我已经在使用 Json.NET 而不是内置的。我可能需要自己调用 JsonConverter 虽然我希望只是将 Serializer 和 Deserializer 设置为 Json.NET 序列化程序就足够了,不幸的是它不是。
    • 嗯,如果您使用的是 Json.Net 序列化程序,您是如何收到您在问题中发布的“无法转换类型为'RestSharp.JsonArray' 的对象”错误的? Json.Net 没有JsonArray 类型;它使用JArray。 RestSharp 的 SimpleJson 序列化程序使用JsonArray。因此,如果您收到该错误,这似乎表明 RestSharp 仍在使用其内部序列化程序而不是 Json.Net。您愿意发布您用于设置序列化程序的代码吗?
    • 我发现了问题。我忘了用 AddHandler 添加处理程序,就像您在回答中提到的那样。我的反序列化器从未被调用过。
    • 啊,是的,这可以解释事情。很高兴您能找到问题所在。
    • 我们在类中添加了一个绑定列表,突然出现了这个错误。没有意识到 RestSahrp 使用了自己版本的 json 序列化程序。选项 1 救了我,谢谢!!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多