JSON反序列化List <someobject>无法正常工作</someobject>

时间:2013-02-14 13:15:08

标签: c# json c#-4.0

我们使用C#System.Runtime.Serialization.Json.DataContractJsonSerializer反序列化JSON。它适用于普通对象,但不适用于List。

例如,如果json字符串在下面,那么它可以正常工作:

{"CacheInsertDateTime":"\/Date(1360761324878)\/","Data":{"__type":"SomeObject:#ConsoleApplication1","Symbol":"some string"}}

但如果josn低于:

{"CacheInsertDateTime":"\/Date(1360761324878)\/","Data":[{"__type":"SomeObject:#ConsoleApplication1","Symbol":"some string"},{"__type":"SomeObject:#ConsoleApplication1","Symbol":"some other string"}]}

数据来自List<Object>而非List<SomeObject>。我也附上了样品溶液,显示出同样的问题。任何帮助或指示都表示赞赏。

编辑:添加了代码

{

命名空间ConsoleApplication1           {     课程     {         / * Someobject类* /         [DataContract]         公共类SomeObject         {             public SomeObject(string sym)             {                 this.Symbol = sym;             }             [数据成员]             public string Symbol {get;组; }

    }
    /* Cahe Data */
    [DataContract()]
    [KnownType("GetKnownTypes")]
    class CacheData
    {
        [DataMember()]
        public object Data { get; set; }

        [DataMember()]
        public DateTime CacheInsertDateTime { get; set; }

        public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
        {
            return GetKnownTypes();
        }
        public static IEnumerable<Type> GetKnownTypes()
        {
            if (knownTypes == null)
            {
                // Since reflection is costly, we will do the lookup once for the known types and persist the data in knownTypes variable
                knownTypes = new List<Type>();

                // first add types from DataModel assembly get types which are marked with DataContract attribute
                var typesInCurrentAssembly = Assembly.GetExecutingAssembly().GetTypes().Where
                    (t => t.GetCustomAttributes(false).Any(attrib => attrib is DataContractAttribute));
                foreach (var type in typesInCurrentAssembly)
                {
                    // add type and list<type> also to the known types list
                    knownTypes.Add(type);
                    knownTypes.Add(typeof(List<>).MakeGenericType(type));
                }

                knownTypes.Add(typeof(DataTable));
            }
            return knownTypes;
        }
        private static List<Type> knownTypes = null;
    }

    /*Cache Response Class*/
    class CacheResponse<T> where T : class
    {
        public CacheData CacheData { get; set; }
        public T Data
        {
            get{return (CacheData != null && CacheData.Data.GetType() == typeof(T)) ? CacheData.Data as T: null;}
        }
    }
    /* Main class */
    static void Main(string[] args)
    {   
        //1. first with someobject, it works same as above
        string jsonString = "{\"CacheInsertDateTime\":\"\\/Date(1360761324878)\\/\",\"Data\":{\"__type\":\"SomeObject:#ConsoleApplication1\",\"Symbol\":\"some object 1\"}}";
        CacheData obj = null;
        byte[] byteData = Encoding.UTF8.GetBytes(jsonString);
        using (MemoryStream stream = new MemoryStream(byteData))
        {
            var serializer = new DataContractJsonSerializer(typeof(CacheData));
            obj = serializer.ReadObject(stream) as CacheData;
        }
        CacheResponse<SomeObject> response1 = new CacheResponse<SomeObject>();
        response1.CacheData = obj;
        SomeObject responseObj = response1.Data; //this response object is fine            

        //2. with list<someobject>, it does not work
        jsonString = "{\"CacheInsertDateTime\":\"\\/Date(1360761324878)\\/\",\"Data\":[{\"__type\":\"SomeObject:#ConsoleApplication1\",\"Symbol\":\"some object 1\"},{\"__type\":\"SomeObject:#ConsoleApplication1\",\"Symbol\":\"some object 2\"}]}";
        byteData = Encoding.UTF8.GetBytes(jsonString);
        using (MemoryStream stream = new MemoryStream(byteData))
        {
            var serializer = new DataContractJsonSerializer(typeof(CacheData));
            obj = serializer.ReadObject(stream) as CacheData;
        }
        CacheResponse<List<SomeObject>> response2 = new CacheResponse<List<SomeObject>>();
        response2.CacheData = obj;
        List<SomeObject> responseList = response2.Data;//this is null            
    }
}

}

1 个答案:

答案 0 :(得分:0)

确保让序列化程序知道列表中的预期类型,例如将其传递给DataContractJsonSerializer的构造函数。

以下示例按预期工作:

namespace ConsoleApplication1
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Runtime.Serialization.Json;
    using System.Text;

    public class SomeObject
    {
        public string Symbol { get; set; }
    }

    public class MyClass
    {
        public DateTime CacheInsertTime { get; set; }
        public List<object> Data { get; set; }
    }

    public class Program
    {
        private const string JsonString = @"{""CacheInsertDateTime"":""\/Date(1360761324878)\/"",""Data"":[{""__type"":""SomeObject:#ConsoleApplication1"",""Symbol"":""some string""},{""__type"":""SomeObject:#ConsoleApplication1"",""Symbol"":""some other string""}]}";

        private static void Main()
        {
            var ser = new DataContractJsonSerializer(typeof (MyClass), new[] {typeof (SomeObject)});
            var ms = new MemoryStream(Encoding.ASCII.GetBytes(JsonString));

            var obj = (MyClass) ser.ReadObject(ms);
            Trace.Assert(obj.Data.Count == 2);
            Trace.Assert(((SomeObject) obj.Data[1]).Symbol == "some other string");
        }
    }
}

注意我是如何将typeof(SomeType)传递给序列化器的构造函数。