215 votes

.NET comment sérialiser un TimeSpan à XML

Je suis en train de sérialiser un .NET TimeSpan objet XML et il ne fonctionne pas. Un rapide google a suggéré que, même TimeSpan est sérialisable, l' XmlCustomFormatter ne permet pas de fournir des méthodes pour convertir TimeSpan des objets vers et à partir de XML.

Une suggestion a été d'ignorer l' TimeSpan pour la sérialisation, et, au lieu de sérialiser le résultat d' TimeSpan.Ticks ( new TimeSpan(ticks) pour la désérialisation). Un exemple de ce qui suit:

[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); }
    }
}

Bien que cela semble fonctionner dans mon test - est-ce la meilleure façon d'atteindre cet objectif?

Est-il une meilleure façon de sérialiser un laps de Temps et à partir de XML?

114voto

Rory MacLeod Points 4574

Ceci est seulement une légère modification de l'approche suggérée dans la question, mais ce problème Microsoft Connect recommande d'utiliser une propriété pour la sérialisation comme ceci:

 [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); 
    }
}
 

Ceci sérialiserait un TimeSpan de 0:02:45 comme:

 <TimeSinceLastEvent>PT2M45S</TimeSinceLastEvent>
 

Alternativement, le DataContractSerializer supporte TimeSpan.

72voto

Marc Gravell Points 482669

La façon dont vous l'ai déjà posté est probablement le plus propre. Si vous n'aimez pas le supplément de propriété, vous pourriez mettre en oeuvre IXmlSerializable, mais alors vous devez faire tout cequi largement défait le point. Je serais heureux de se servir de l'approche que vous avez posté; il est (par exemple) efficace (pas de complexes d'analyse, etc), de la culture indépendante, sans ambiguïté, et d'horodatage type numéros sont faciles à comprendre.

En aparté, j'ajoute souvent:

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

Cela vient se cache dans l'INTERFACE utilisateur et le référencement des dll pour éviter toute confusion.

31voto

Wes Points 279

Quelque chose qui peut fonctionner dans certains cas est de donner à votre propriété publique un champ de support, qui est un TimeSpan, mais la propriété publique est exposée comme une chaîne.

par exemple:

 protected TimeSpan myTimeout;
public string MyTimeout 
{ 
    get { return myTimeout.ToString(); } 
    set { myTimeout = TimeSpan.Parse(value); }
}
 

C'est correct si la valeur de la propriété est utilisée principalement avec w / dans la classe ou les classes héritantes et est chargée à partir de la configuration xml.

Les autres solutions proposées sont meilleures si vous souhaitez que la propriété publique soit une valeur TimeSpan utilisable pour les autres classes.

10voto

phoog Points 22667

Vous pouvez créer un wrapper léger autour de la structure 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());
        }
    }
}
 

Exemple de résultat sérialisé:

 <Entry>
  <StartTime>2010-12-06T08:45:12.5</StartTime>
  <Duration>2.08:29:35.2500000</Duration>
</Entry>
 

8voto

Rune Grimstad Points 17775

Une option plus lisible consisterait à sérialiser en tant que chaîne et à utiliser la méthode TimeSpan.Parse pour la désérialiser. Vous pouvez faire la même chose que dans votre exemple mais en utilisant TimeSpan.ToString () dans le getter et TimeSpan.Parse (value) dans le setter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X