如何使用DataContractJsonSerializer反序列化特定元素

时间:2016-02-07 01:51:12

标签: c# json deserialization datacontractserializer

我试图用DataContractJsonSerializer类反序列化json数据。问题是如何设置根元素?

我的json数据在这里。

{
   "delete":{
      "status":{
         "id":696142765093072896,
         "id_str":"696142765093072896",
         "user_id":2223183576,
         "user_id_str":"2223183576"
      },
      "timestamp_ms":"1454808363540"
   }
}

我像这样为反序列化编写了类。但它不起作用。我的Status始终为空。

[DataContract(Name="delete")]
public class Delete
{
    [DataMember(Name="status")]
    public DeletedStatus Status { get; set; }
}

public class DeletedStatus
{
    [DataMember(Name = "id")]
    public long Id { get; set; }
    [DataMember(Name = "user_id")]
    public long UserId { get; set; }
}

如何从特定元素开始解析json?

1 个答案:

答案 0 :(得分:1)

根据我从JSON中可以看出的情况,反序列化似乎失败了,因为对象的root属性是" delete"属性。我不相信这会对DataContractJsonSerializer起作用,因为给定的类型与Delete类型不匹配。另一个可能的问题是我看到DeleteStatus类缺少[DataContract]属性。

长话短说,没有简单的方法可以做你想做的事。话虽如此,有一种简短而又甜蜜的方式可以对JSON进行反序列化,而不会增加额外的麻烦。我建议创建一个表示当前状态的JSON的数据类型,然后反序列化为该类型。

我编写了一个可以从Visual Studio测试项目运行的单元测试。我希望这会有所帮助。

<强> JsonDeserializationTests.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Runtime.Serialization.Json;
using System.IO;

namespace SerializationTests {
    [TestClass]
    public class JsonDeserializationTests {
        [TestMethod]
        public void Deserialize_Delete_Type_Success() {
            string json = string.Empty;
            //Set the DataContractJsonSerializer target type to our wrapper type.
            var ser = new DataContractJsonSerializer(typeof(DeleteWrapperJsonResult));
            //Create an instance of the wrapper that reflects the JSON  that you gave.
            //This will help me mock the data that you gave.
            var deleteWrapper = new DeleteWrapperJsonResult {
                delete = new DeleteJsonResult {
                    status = new DeletedStatusJsonResult {
                        id = 696142765093072896,
                        user_id = 2223183576
                    }
                }
            };
            //Convert the mock data to JSON to reflect the JSON that you gave.
            using (var serStream = new MemoryStream()) {
                using (var sr = new StreamReader(serStream)) {
                    ser.WriteObject(serStream, deleteWrapper);
                    serStream.Position = 0;
                    json = sr.ReadToEnd(); //Set the JSON string here.
                    //Output "{\"delete\":{\"status\":{\"id\":696142765093072896,\"id_str\":\"696142765093072896\",\"user_id\":2223183576,\"user_id_str\":\"2223183576\"}}}"
                }
            }
            //Prepeare to Deserialize the JSON.
            var deserialized = default(DeleteWrapperJsonResult);
            using (var deserStream = new MemoryStream()) {
                using (var sw = new StreamWriter(deserStream)) {
                    sw.Write(json); //Write the JSON to the MemoryStream
                    sw.Flush();
                    deserStream.Seek(0, SeekOrigin.Begin);
                    //Deserialize the JSON into an instance of our wrapper class.
                    //This works because of the structure of the JSON.
                    deserialized = (DeleteWrapperJsonResult)ser.ReadObject(deserStream);
                }
            }
            //Initialize the actual Delete instanace with what was deserialized.
            var delete = new Delete {
                Status = new DeletedStatus {
                    //These values were populated with the JSON values.
                    UserId = deserialized.delete.status.user_id,
                    Id = deserialized.delete.status.id
                }
            };
            //Write asserts around what was given and check for equality.
            Assert.AreEqual(delete.Status.UserId, deleteWrapper.delete.status.user_id);
            Assert.AreEqual(delete.Status.Id, deleteWrapper.delete.status.id);
            //Test Passes for Me
        }
    }
}

<强> Delete.cs

using System.Runtime.Serialization;

namespace SerializationTests {
    [DataContract]
    [KnownType(typeof(Delete))]
    public class Delete {
        [DataMember]
        public DeletedStatus Status { get; set; }
    }

    [DataContract]
    [KnownType(typeof(DeletedStatus))]
    public class DeletedStatus {
        [DataMember]
        public long Id { get; set; }
        [DataMember]
        public long UserId { get; set; }

    }

    /**************************************************************
     These types below are what comprise our wrapper class so that we can
     use the JSON in its current state. The wrapper classes have properties that
     are synonymous with the JSON properties.
     **************************************************************/
    //This structure represents the object nesting as it appears currently in your example.
    [DataContract]
    [KnownType(typeof(DeleteJsonResult))]
    public class DeleteWrapperJsonResult {
        [DataMember]
        public DeleteJsonResult delete { get; set; }
    }

    [DataContract]
    [KnownType(typeof(DeleteJsonResult))]
    public class DeleteJsonResult {
        [DataMember]
        public DeletedStatusJsonResult status { get; set; }
    }

    [DataContract]
    [KnownType(typeof(DeletedStatusJsonResult))]
    public class DeletedStatusJsonResult {
        [DataMember]
        public long id { get; set; }
        [DataMember]
        public string id_str {
            get {
                return id.ToString();
            }
            set {
                return;
            }
        }
        [DataMember]
        public long user_id { get; set; }
        [DataMember]
        public string user_id_str {
            get {
                return user_id.ToString();
            }
            set {
                return;
            }
        }
    }
}

截至撰写本文时,我的单元测试正在通过!如果我能进一步协助,请告诉我。

相关问题