.NET TimeSpan
객체를 XML 로 직렬화하려고하는데 작동하지 않습니다. 빠른 구글 TimeSpan
은 직렬화가 가능하지만XmlCustomFormatter
TimeSpan
객체를 XML 로 변환 하거나 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과 TimeSpan을 직렬화하는 더 좋은 방법이 있습니까?
답변
이미 게시 한 방법이 가장 깨끗할 것입니다. 추가 속성이 마음에 들지 않으면을 구현할 수 IXmlSerializable
있지만 모든 작업을 수행해야합니다. 하므로 요점을 크게 잃습니다. 나는 당신이 게시 한 접근법을 행복하게 사용합니다. (예를 들어) 효율적 (복잡한 구문 분석 등이 아님), 문화 독립적, 명확하고 타임 스탬프 유형 숫자는 쉽고 일반적으로 이해됩니다.
제쳐두고, 나는 종종 다음을 추가합니다 :
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
혼란을 피하기 위해 UI와 dll 참조에서 숨길 수 있습니다.
답변
이것은 질문에서 제안한 접근 방식의 약간의 수정일 뿐이지 만이 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);
}
}
이것은 다음과 같이 TimeSpan을 0:02:45로 직렬화합니다.
<TimeSinceLastEvent>PT2M45S</TimeSinceLastEvent>
또는 DataContractSerializer
TimeSpan을 지원합니다.
답변
경우에 따라 작동 할 수있는 것은 공용 속성에 백업 필드 (TimeSpan)를 제공하는 것이지만 공용 속성은 문자열로 노출됩니다.
예 :
protected TimeSpan myTimeout;
public string MyTimeout
{
get { return myTimeout.ToString(); }
set { myTimeout = TimeSpan.Parse(value); }
}
속성 값이 포함 클래스 또는 상속 클래스와 함께 주로 사용되고 XML 구성에서로드 된 경우에는 괜찮습니다.
제안 된 다른 솔루션은 공용 속성을 다른 클래스에 유용한 TimeSpan 값으로 사용하려는 경우 더 좋습니다.
답변
의 응답을 결합 컬러 직렬화 및 이 원래의 솔루션을 (그 자체로 큰 인) 나는이 솔루션을 가지고 :
[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); }
}
}
답변
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());
}
}
}
직렬화 된 결과 샘플 :
<Entry>
<StartTime>2010-12-06T08:45:12.5</StartTime>
<Duration>2.08:29:35.2500000</Duration>
</Entry>
답변
보다 읽기 쉬운 옵션은 문자열 TimeSpan.Parse
로 직렬화 하고 메소드를 사용하여 직렬화 해제하는 것입니다. 예와 동일하지만 TimeSpan.ToString()
getter 및 TimeSpan.Parse(value)
setter에서 사용할 수 있습니다.
답변
또 다른 옵션은 SoapFormatter
클래스가 아닌 클래스를 사용하여 직렬화하는 것 XmlSerializer
입니다.
결과 XML 파일은 약간 다른 “SOAP”접두어 태그 등으로 보이지만 그렇게 할 수는 있습니다.
다음 SoapFormatter
은 20 시간 28 분의 시간 범위를 직렬화 한 것입니다.
<myTimeSpan>P0Y0M0DT20H28M0S</myTimeSpan>
SOAPFormatter 클래스를 사용하려면 System.Runtime.Serialization.Formatters.Soap
동일한 이름의 네임 스페이스에 대한 참조를 추가 하고 사용해야합니다.
