C# 如何将 TimeSpan 序列化为 XML
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/637933/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to serialize a TimeSpan to XML
提问by joeldixon66
I am trying to serialize a .NET TimeSpan
object to XML and it is not working. A quick google has suggested that while TimeSpan
is serializable, the XmlCustomFormatter
does not provide methods to convert TimeSpan
objects to and from XML.
我正在尝试将 .NETTimeSpan
对象序列化为XML,但它不起作用。一个快速的谷歌建议虽然TimeSpan
是可序列化的,XmlCustomFormatter
但不提供将TimeSpan
对象转换为 XML 或从 XML转换的方法。
One suggested approach was to ignore the TimeSpan
for serialization, and instead serialize the result of TimeSpan.Ticks
(and use new TimeSpan(ticks)
for deserialization). An example of this follows:
一种建议的方法是忽略TimeSpan
for 序列化,而是将结果序列化TimeSpan.Ticks
(并new TimeSpan(ticks)
用于反序列化)。一个例子如下:
[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); }
}
}
While this appears to work in my brief testing - is this the best way to achieve this?
虽然这在我的简短测试中似乎有效 - 这是实现这一目标的最佳方法吗?
Is there a better way to serialize a TimeSpan to and from XML?
有没有更好的方法将 TimeSpan 序列化为 XML 或从 XML 序列化?
采纳答案by Marc Gravell
The way you've already posted is probably the cleanest. If you don't like the extra property, you could implement IXmlSerializable
, but then you have to do everything, which largely defeats the point. I'd happily use the approach you've posted; it is (for example) efficient (no complex parsing etc), culture independent, unambiguous, and timestamp-type numbers are easily and commonly understood.
您已经发布的方式可能是最干净的。如果你不喜欢额外的属性,你可以实现IXmlSerializable
,但是你必须做所有的事情,这在很大程度上违背了这一点。我很乐意使用您发布的方法;它(例如)高效(没有复杂的解析等)、文化独立、明确且时间戳类型的数字很容易理解。
As an aside, I often add:
顺便说一句,我经常补充:
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
This just hides it in the UI and in referencing dlls, to avoid confusion.
这只是将它隐藏在 UI 和引用 dll 中,以避免混淆。
回答by Rune Grimstad
A more readable option would be to serialize as a string and use the TimeSpan.Parse
method to deserialize it. You could do the same as in your example but using TimeSpan.ToString()
in the getter and TimeSpan.Parse(value)
in the setter.
一个更具可读性的选项是将序列化为字符串并使用该TimeSpan.Parse
方法对其进行反序列化。您可以执行与示例相同的操作,但TimeSpan.ToString()
在 getter 和TimeSpan.Parse(value)
setter 中使用。
回答by Marc Gravell
Another option would be to serialize it using the SoapFormatter
class rather than the XmlSerializer
class.
另一种选择是使用SoapFormatter
类而不是XmlSerializer
类来序列化它。
The resulting XML file looks a little different...some "SOAP"-prefixed tags, etc...but it can do it.
生成的 XML 文件看起来有点不同……一些“SOAP”前缀标签等……但它可以做到。
Here's what SoapFormatter
serialized a timespan of 20 hours and 28 minutes serialized to:
以下是SoapFormatter
序列化 20 小时 28 分钟的时间跨度序列化为:
<myTimeSpan>P0Y0M0DT20H28M0S</myTimeSpan>
To use SOAPFormatter class, need to add reference to System.Runtime.Serialization.Formatters.Soap
and use the namespace of the same name.
要使用 SOAPFormatter 类,需要添加引用System.Runtime.Serialization.Formatters.Soap
并使用同名的命名空间。
回答by phoog
You could create a light wrapper around the TimeSpan struct:
您可以围绕 TimeSpan 结构创建一个轻型包装器:
namespace My.XmlSerialization
{
public struct TimeSpan : IXmlSerializable
{
private System.TimeSpan _value;
public static implicit operator TimeSpan(System.TimeSpan value)
{
return new TimeSpan { _value = value };
}
public static implicit operator System.TimeSpan(TimeSpan value)
{
return value._value;
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
_value = System.TimeSpan.Parse(reader.ReadContentAsString());
}
public void WriteXml(XmlWriter writer)
{
writer.WriteValue(_value.ToString());
}
}
}
Sample serialized result:
示例序列化结果:
<Entry>
<StartTime>2010-12-06T08:45:12.5</StartTime>
<Duration>2.08:29:35.2500000</Duration>
</Entry>
回答by Rory MacLeod
This is only a slight modification on the approach suggested in the question, but this Microsoft Connect issuerecommends using a property for serialization like this:
这只是对问题中建议的方法的轻微修改,但此 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);
}
}
This would serialize a TimeSpan of 0:02:45 as:
这会将 0:02:45 的 TimeSpan 序列化为:
<TimeSinceLastEvent>PT2M45S</TimeSinceLastEvent>
Alternatively, the DataContractSerializer
supports TimeSpan.
或者,DataContractSerializer
支持 TimeSpan。
回答by Wes
Something that can work in some cases is to give your public property a backing field, which is a TimeSpan, but the public property is exposed as a string.
在某些情况下可行的方法是为您的公共财产提供一个支持字段,即 TimeSpan,但公共财产作为字符串公开。
eg:
例如:
protected TimeSpan myTimeout;
public string MyTimeout
{
get { return myTimeout.ToString(); }
set { myTimeout = TimeSpan.Parse(value); }
}
This is ok if the property value is used mostly w/in the containing class or inheriting classes and is loaded from xml configuration.
如果属性值主要在包含类或继承类中使用并从 xml 配置加载,则这是可以的。
The other proposed solutions are better if you want the public property to be a usable TimeSpan value for other classes.
如果您希望公共属性成为其他类的可用 TimeSpan 值,则其他建议的解决方案会更好。
回答by Manvendra
Try this :
尝试这个 :
//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); }
}
回答by JRS
For data contract serialization I use the following.
对于数据合同序列化,我使用以下内容。
- Keeping the serialized property private keeps the public interface clean.
- Using the public property name for serialization keeps the XML clean.
- 保持序列化属性私有可以保持公共接口干净。
- 使用公共属性名称进行序列化可以保持 XML 干净。
Public Property Duration As TimeSpan
<DataMember(Name:="Duration")>
Private Property DurationString As String
Get
Return Duration.ToString
End Get
Set(value As String)
Duration = TimeSpan.Parse(value)
End Set
End Property
回答by Mikhail
Combining an answer from Color serializationand this original solution(which is great by itself) I got this solution:
结合Color 序列化的答案和这个原始解决方案(这本身就很棒),我得到了这个解决方案:
[XmlElement(Type = typeof(XmlTimeSpan))]
public TimeSpan TimeSinceLastEvent { get; set; }
where XmlTimeSpan
class is like this:
其中XmlTimeSpan
类是这样的:
public class XmlTimeSpan
{
private const long TICKS_PER_MS = TimeSpan.TicksPerMillisecond;
private TimeSpan m_value = TimeSpan.Zero;
public XmlTimeSpan() { }
public XmlTimeSpan(TimeSpan source) { m_value = source; }
public static implicit operator TimeSpan?(XmlTimeSpan o)
{
return o == null ? default(TimeSpan?) : o.m_value;
}
public static implicit operator XmlTimeSpan(TimeSpan? o)
{
return o == null ? null : new XmlTimeSpan(o.Value);
}
public static implicit operator TimeSpan(XmlTimeSpan o)
{
return o == null ? default(TimeSpan) : o.m_value;
}
public static implicit operator XmlTimeSpan(TimeSpan o)
{
return o == default(TimeSpan) ? null : new XmlTimeSpan(o);
}
[XmlText]
public long Default
{
get { return m_value.Ticks / TICKS_PER_MS; }
set { m_value = new TimeSpan(value * TICKS_PER_MS); }
}
}
回答by Gildor
My version of the solution :)
我的解决方案版本:)
[DataMember, XmlIgnore]
public TimeSpan MyTimeoutValue { get; set; }
[DataMember]
public string MyTimeout
{
get { return MyTimeoutValue.ToString(); }
set { MyTimeoutValue = TimeSpan.Parse(value); }
}
Edit: assuming it is nullable...
编辑:假设它可以为空...
[DataMember, XmlIgnore]
public TimeSpan? MyTimeoutValue { get; set; }
[DataMember]
public string MyTimeout
{
get
{
if (MyTimeoutValue != null)
return MyTimeoutValue.ToString();
return null;
}
set
{
TimeSpan outValue;
if (TimeSpan.TryParse(value, out outValue))
MyTimeoutValue = outValue;
else
MyTimeoutValue = null;
}
}