如何serialize时间跨度为XML
-
10-07-2019 - |
题
我想serialize。净 TimeSpan
目XML和它不工作。一个快速的谷歌建议,而 TimeSpan
是序列化, XmlCustomFormatter
不提供转换方法 TimeSpan
对象与XML。
一个建议的做法是忽略 TimeSpan
对于化,而不是列化的结果 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); }
}
}
虽然这显示工作,在我简要测试-这是最好的方式来实现这一目标?
是否有更好的办法以化的时间跨度从XML?
解决方案
您已经发布的方法可能是最干净的。如果你不喜欢额外的属性,你可以实现IXmlSerializable
,但你必须做的所有,这在很大程度上违背了点。我会愉快地使用您发布的办法;它是(例如)高效(无复杂的分析等),独立培养的,明确的和时间戳记型号码容易且通常理解的。
顺便说一句,我经常补充:
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
这只是隐藏它在用户界面和在引用的DLL,以避免混淆。
其他提示
这仅仅是一个轻微的修改的方法提出的问题,但是 这Microsoft连接问题 建议使用的财产的序列化这样的:
[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);
}
}
这将serialize时间跨度为0:02:45:
<TimeSinceLastEvent>PT2M45S</TimeSinceLastEvent>
或者, DataContractSerializer
支持时间跨度。
东西,可以在某些情况下,工作就是给你的公共财产的背场,这是一个时间跨度,但公共财产公开为一个字符串。
例如:
protected TimeSpan myTimeout;
public string MyTimeout
{
get { return myTimeout.ToString(); }
set { myTimeout = TimeSpan.Parse(value); }
}
如果属性值大多采用瓦特/包含类或继承的类,并且从XML配置加载这是确定
如果你希望公众属性为其他类的可用时间跨度值等提出的解决方案是更好的。
结合一个答案 颜色列化 和 这个原来的解决方案 (这是伟大的本身)我得到了这个解决方案:
[XmlElement(Type = typeof(XmlTimeSpan))]
public TimeSpan TimeSinceLastEvent { get; set; }
哪里 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); }
}
}
您可以创建围绕时间跨度结构光包装:
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());
}
}
}
样本串行化结果:
<Entry>
<StartTime>2010-12-06T08:45:12.5</StartTime>
<Duration>2.08:29:35.2500000</Duration>
</Entry>
一个更可读的选择是将序列作为一个字符串,并使用TimeSpan.Parse
方法来反序列化。你可以做一样的例子,但在使用的getter和TimeSpan.ToString()
TimeSpan.Parse(value)
的制定者。
另一种选择是使用SoapFormatter
类而非XmlSerializer
类序列化它。
在生成的XML文件看起来有点不同......一些“SOAP” -prefixed标签,等等...但它可以做到这一点。
下面就是System.Runtime.Serialization.Formatters.Soap
序列序列化到20小时28分钟时间跨度:
<myTimeSpan>P0Y0M0DT20H28M0S</myTimeSpan>
要使用SoapFormatter类,需要添加参考<=>并使用相同的名称的名称空间。
我的版本的溶液:)
[DataMember, XmlIgnore]
public TimeSpan MyTimeoutValue { get; set; }
[DataMember]
public string MyTimeout
{
get { return MyTimeoutValue.ToString(); }
set { MyTimeoutValue = TimeSpan.Parse(value); }
}
编辑:假设它是可空...
[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;
}
}
存储在XML作为秒数时间跨度,但它很容易通过,希望。 时间跨度手动序列化(实施IXmlSerializable的):
public class Settings : IXmlSerializable
{
[XmlElement("IntervalInSeconds")]
public TimeSpan Interval;
public XmlSchema GetSchema()
{
return null;
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("IntervalInSeconds", ((int)Interval.TotalSeconds).ToString());
}
public void ReadXml(XmlReader reader)
{
string element = null;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
element = reader.Name;
else if (reader.NodeType == XmlNodeType.Text)
{
if (element == "IntervalInSeconds")
Interval = TimeSpan.FromSeconds(double.Parse(reader.Value.Replace(',', '.'), CultureInfo.InvariantCulture));
}
}
}
}
有更全面例如: https://bitbucket.org/njkazakov/timespan-serialization
看Settings.cs。 并有一些棘手的代码使用XmlElementAttribute。
对数据的合同序列使用的以下。
- 保持化财产的私人保持公众口干净。
- 使用公共财产的名字列化保持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
如果你不希望任何解决方法,使用的DataContractSerializer类从System.Runtime.Serialization.dll。
using (var fs = new FileStream("file.xml", FileMode.Create))
{
var serializer = new DataContractSerializer(typeof(List<SomeType>));
serializer.WriteObject(fs, _items);
}
尝试这种情况:
//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); }
}