我试图将. net TimeSpan对象序列化为XML,但它不起作用。快速谷歌表明,虽然TimeSpan是可序列化的,但XmlCustomFormatter没有提供将TimeSpan对象转换为XML或从XML转换的方法。

一种建议的方法是忽略TimeSpan进行序列化,而是序列化TimeSpan的结果。刻度(并使用新的TimeSpan(刻度)进行反序列化)。下面是一个例子:

[Serializable]
public class MyClass
{
    // Local Variable
    private TimeSpan m_TimeSinceLastEvent;

    // Public Property - XmlIgnore as it doesn't serialize anyway
    [XmlIgnore]
    public TimeSpan TimeSinceLastEvent
    {
        get { return m_TimeSinceLastEvent; }
        set { m_TimeSinceLastEvent = value; }
    }

    // Pretend property for serialization
    [XmlElement("TimeSinceLastEvent")]
    public long TimeSinceLastEventTicks
    {
        get { return m_TimeSinceLastEvent.Ticks; }
        set { m_TimeSinceLastEvent = new TimeSpan(value); }
    }
}

虽然这在我的简短测试中似乎是有效的,但这是实现这一目标的最佳方式吗?

是否有更好的方法将TimeSpan与XML进行序列化?


当前回答

你已经发布的方式可能是最干净的。如果您不喜欢这个额外的属性,您可以实现IXmlSerializable,但是您必须完成所有的事情,这在很大程度上违背了重点。我很乐意使用你发布的方法;例如,它是高效的(没有复杂的解析等)、区域性独立、无歧义的,并且时间戳类型的数字易于理解和普遍理解。

顺便说一句,我经常补充:

[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]

这只是将它隐藏在UI和引用dll中,以避免混淆。

其他回答

你已经发布的方式可能是最干净的。如果您不喜欢这个额外的属性,您可以实现IXmlSerializable,但是您必须完成所有的事情,这在很大程度上违背了重点。我很乐意使用你发布的方法;例如,它是高效的(没有复杂的解析等)、区域性独立、无歧义的,并且时间戳类型的数字易于理解和普遍理解。

顺便说一句,我经常补充:

[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]

这只是将它隐藏在UI和引用dll中,以避免混淆。

试试这个:

//Don't Serialize Time Span object.
        [XmlIgnore]
        public TimeSpan m_timeSpan;
//Instead serialize (long)Ticks and instantiate Timespan at time of deserialization.
        public long m_TimeSpanTicks
        {
            get { return m_timeSpan.Ticks; }
            set { m_timeSpan = new TimeSpan(value); }
        }

另一种选择是使用SoapFormatter类而不是XmlSerializer类来序列化它。

结果的XML文件看起来有点不同…一些“SOAP”前缀标签,等等……但它可以做到。

下面是SoapFormatter将一个20小时28分钟的时间跨度序列化为:

<myTimeSpan>P0Y0M0DT20H28M0S</myTimeSpan>

要使用SOAPFormatter类,需要添加对System.Runtime.Serialization.Formatters.Soap的引用,并使用同名的命名空间。

这只是对问题中建议的方法进行了轻微的修改,但是这个Microsoft Connect问题建议使用这样的属性进行序列化:

[XmlIgnore]
public TimeSpan TimeSinceLastEvent
{
    get { return m_TimeSinceLastEvent; }
    set { m_TimeSinceLastEvent = value; }
}

// XmlSerializer does not support TimeSpan, so use this property for 
// serialization instead.
[Browsable(false)]
[XmlElement(DataType="duration", ElementName="TimeSinceLastEvent")]
public string TimeSinceLastEventString
{
    get 
    { 
        return XmlConvert.ToString(TimeSinceLastEvent); 
    }
    set 
    { 
        TimeSinceLastEvent = string.IsNullOrEmpty(value) ?
            TimeSpan.Zero : XmlConvert.ToTimeSpan(value); 
    }
}

这将序列化0:02:45的TimeSpan为:

<TimeSinceLastEvent>PT2M45S</TimeSinceLastEvent>

或者,DataContractSerializer支持TimeSpan。

对于。net 6和。net 7, TimeSpan序列化可以开箱即用。格式是XSD“duration”数据类型的格式。所以“14:30”被序列化为PT14H30M

对于.NET Framework 4.8,这个行为可以通过这个开关激活:

AppContext.SetSwitch("Switch.System.Xml.EnableTimeSpanSerialization", true);