1

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

例如,如果 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>。我还附上了示例解决方案,显示了同样的问题。任何帮助或方向表示赞赏。

编辑:添加了代码

{

namespace ConsoleApplication1 { class Program { /* Someobject 类*/ [DataContract] public class SomeObject { public SomeObject(string sym) { this.Symbol = sym; } [DataMember] 公共字符串符号 { 获取;放; }

    }
    /* 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            
    }
}

}

4

1 回答 1

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) 传递给序列化程序的构造函数。

于 2013-02-14T13:30:26.483 回答