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

How to deserialize specific element with DataContractJsonSerializer

我正在尝试使用 DataContractJsonSerializer class 反序列化 json 数据。问题是如何设置根元素?

我的 json 数据在这里。

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

我写了class这样的反序列化。但这是行不通的。我的 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?

根据我从 JSON 中得知的信息,反序列化似乎失败了,因为对象的根 属性 是 "delete" 属性。我不相信这会与 DataContractJsonSerializer 一起工作,因为给定的类型与 Delete 类型不匹配。另一个可能的问题是我看到 DeleteStatus class 缺少 [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;
            }
        }
    }
}

截至撰写本文时,我的单元测试已通过!让我知道是否可以提供进一步帮助。