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

时间:2016-07-12 22:26:40

标签: inheritance datacontractserializer

我有一个TimeDetails类,它有一组TimeRanges。 此类已序列化并存储到DB。

以前的列表是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; }
    }
}

1 个答案:

答案 0 :(得分:0)

为了向后兼容,您应该保留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中的成员顺序很重要。