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>。同じ問題を示すサンプルソリューションも添付しました。どんな助けや指示も大歓迎です。

編集:コードを追加

{

名前空間 ConsoleApplication1 { クラス プログラム { /* Someobject クラス*/ [DataContract] public class SomeObject { public SomeObject(string sym) { this.Symbol = sym; [DataMember] 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            
    }
}

}

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 に答える