DatacontractSerializer 不会将基类型序列化为继承类型

DatacontractSerializer does not serialize base type to inherited type

我有一个包含 TimeRanges 集合的 TimeDetails class。 这个 class 被序列化并存储到数据库中。

列表曾经是 DateTimeRange 类型。现在我必须向它添加一个新的 属性 (SomeId)。所以我把它继承给了AvailableTimeRange,并在其中添加了SomeId 属性。 (我必须按原样保留 DateTimeRange,因为它在其他地方使用过。

旧行(具有 DateTimeRange 属性 类型)的反序列化失败。

这是我的单元测试

 using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using mynamespace;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void With_DateTimeRange()
        {
            var xml = "<TimeDetails xmlns=\"http://schemas.datacontract.org/2004/07/mynamespace\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
                      "<TimeList>" +
                      "<DateTimeRange><From>2016-01-21T08:00:00</From><To>2016-01-21T11:00:00</To></DateTimeRange>" +
                      "<DateTimeRange><From>2016-07-12T06:00:00</From><To>2016-07-12T09:00:00</To></DateTimeRange>" +
                      "</TimeList>" +
                      "</TimeDetails>";
            TimeDetails details = TimeDetails.FromXml(xml);
           Assert.AreEqual(2, details.TimeList.Count);
        }

        [TestMethod]
        public void With_AvailableTimeRange()
        {
            var xml =
            "<TimeDetails xmlns=\"http://schemas.datacontract.org/2004/07/mynamespace\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">"+
            "<TimeList>"+
            "<AvailableTimeRange><From>2016-07-12T08:00:00</From><SomeId>100</SomeId><To>2016-07-12T09:00:00</To></AvailableTimeRange>"+
            "</TimeList></TimeDetails>";

            var details = TimeDetails.FromXml(xml);
            Assert.AreEqual(1, details.TimeList.Count);
            Assert.IsTrue(details.TimeList[0] is AvailableTimeRange);
            Assert.AreEqual(100, (details.TimeList[0] as AvailableTimeRange).SomeId);
        }
    }
}

namespace mynamespace
{
    public class TimeDetails
    {
        public List<AvailableTimeRange> TimeList { get; set; }

        public static TimeDetails FromXml(string xml)
        {
            if (String.IsNullOrWhiteSpace(xml))
                return null;

            TimeDetails timeDetails;
            byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
            using (MemoryStream ms = new MemoryStream(data))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof (TimeDetails),
                    new[] {typeof (AvailableTimeRange), typeof (DateTimeRange)});
                timeDetails = (TimeDetails) serializer.ReadObject(ms);
            }
            return timeDetails;
        }

    }
    public class DateTimeRange
    {
        public DateTime From { get; set; }
        public DateTime To { get; set; }
    }

    public class AvailableTimeRange : DateTimeRange
    {
        public long? SomeId { get; set; }
    }
}

为了向后兼容,您应该保留 DateTimeRange 列表 - 它可以存储基本类型和派生类型。

public List<DateTimeRange> TimeList { get; set; }

在 xml 中使用 type 属性来识别 AvailableTimeRange 个实例:

<DateTimeRange i:type=\"AvailableTimeRange\"><From>2016-07-12T08:00:00</From><To>2016-07-12T09:00:00</To><SomeId>100</SomeId></DateTimeRange>

注意 - xml 中的成员顺序很重要。