【问题标题】:Which Json deserializer renders IList<T> collections?哪个 Json 反序列化器呈现 IList<T> 集合?
【发布时间】:2010-12-07 17:33:05
【问题描述】:

我正在尝试将 json 反序列化为一个对象模型,其中集合表示为 IList&lt;T&gt; 类型。

真正的反序列化在这里:

JavaScriptSerializer serializer = new JavaScriptSerializer();

return serializer.Deserialize<IList<Contact>>(
    (new StreamReader(General.GetEmbeddedFile("Contacts.json")).ReadToEnd()));

在我发布异常之前,您应该知道隐式转换是什么。这是Contact 类型:

public class Contact
{
    public int ID { get; set; }
    public string Name { get; set; }
    public LazyList<ContactDetail> Details { get; set; }
    //public List<ContactDetail> Details { get; set; }
}

这是ContactDetail 类型:

public class ContactDetail
{
    public int ID { get; set; }
    public int OrderIndex { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

LazyList&lt;T&gt; 要知道的重要一点是它实现了IList&lt;T&gt;

public class LazyList<T> : IList<T>
{
    private IQueryable<T> _query = null;
    private IList<T> _inner = null;
    private int? _iqueryableCountCache = null;


    public LazyList()
    {
        this._inner = new List<T>();
    }

    public LazyList(IList<T> inner)
    {
        this._inner = inner;
    }

    public LazyList(IQueryable<T> query)
    {
        if (query == null)
            throw new ArgumentNullException();
        this._query = query;
    }

现在这个 LazyList&lt;T&gt; 类定义很好,直到我尝试将 Json 反序列化到其中。 System.Web.Script.Serialization.JavaScriptSerializer 似乎想将列表序列化为List&lt;T&gt;,这对它的年龄来说是有意义的,但我需要它们的类型为IList&lt;T&gt;,所以它们将转换为我的LazyList&lt;T&gt;(至少那是我认为我要去的地方错了)。

我得到了这个例外:

System.ArgumentException: Object of type 'System.Collections.Generic.List`1[ContactDetail]' cannot be converted to type 'LazyList`1[ContactDetail]'..

当我尝试在我的 Contact 类型中使用 List&lt;ContactDetail&gt; 时(如您在上面所见),它似乎有效。但我不想使用List&lt;T&gt;'s。我什至尝试让我的LazyList&lt;T&gt;List&lt;T&gt; 继承,这似乎可以执行,但是将List&lt;T&gt; 的内部T[] 传递给我的实现是一场噩梦,我根本不希望List&lt;T&gt; 的膨胀在任何地方我的模型。

我还尝试了一些 other json 库但无济于事(我可能没有充分利用这些库。我或多或少地替换了引用并尝试重复此问题顶部引用的代码。也许传递设置参数会有帮助吗??)。

我现在不知道该尝试什么。我要使用另一个解串器吗?我是否调整反序列化本身?我需要改变我的类型来取悦反序列化器吗?我需要更多地担心隐式转换还是只实现另一个接口?

【问题讨论】:

    标签: c# json serialization ilist implicit-conversion


    【解决方案1】:

    不可能直接反序列化为接口,因为接口只是一个契约。 JavaScriptSerializer 必须反序列化为实现 IList 的具体类型,最合乎逻辑的选择是 List。您必须将 List 转换为 LazyList,鉴于您发布的代码,这应该很容易:

    var list = serializer.Deserialize<IList<Contact>>(...);
    var lazyList = new LazyList(list);
    

    【讨论】:

    • 在底部的代码示例之前,我想我得到的大部分内容都是您所说的。在您发布的示例的第一行中,它将失败。除非您可以建议对我的 LazyList 类进行更改以使其不会失败?
    【解决方案2】:

    不幸的是,您可能需要修复您的类,因为反序列化程序无法知道它应该是 IList 类型,因为 List 是 IList 的实现。

    由于http://json.org 的反序列化器有可用的源代码,您只需修改其中一个即可。

    【讨论】:

    • 你是什么意思“修复你的班级”?你可以说得更详细点吗?我应该修改我的课程还是解串器源? ..或两者兼而有之?
    • 扩展列表,而不是 LazySerializer 的 ILIst。这将是比为序列化程序提供源代码更好的选择,但是,如果您无法更改源代码,那么您需要找到其他东西来更改。
    【解决方案3】:

    我最终使用了Json.NET lib,它对自定义映射有很好的 linq 支持。这就是我的反序列化最终的样子:

            JArray json = JArray.Parse(
                (new StreamReader(General.GetEmbeddedFile("Contacts.json")).ReadToEnd()));
    
            IList<Contact> tempContacts = (from c in json
                                           select new Contact
                                           {
                                               ID = (int)c["ID"],
                                               Name = (string)c["Name"],
                                               Details = new LazyList<ContactDetail>(
                                                   (
                                                       from cd in c["Details"]
                                                       select new ContactDetail
                                                       {
                                                           ID = (int)cd["ID"],
                                                           OrderIndex = (int)cd["OrderIndex"],
                                                           Name = (string)cd["Name"],
                                                           Value = (string)cd["Value"]
                                                       }
                                                    ).AsQueryable()),
                                               Updated = (DateTime)c["Updated"]
                                           }).ToList<Contact>();
    
            return tempContacts;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-02
      • 2017-01-09
      • 1970-01-01
      • 1970-01-01
      • 2010-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多