2011-01-17 19 views
5

Ho un documento XML che io non controllo che dispone di un elemento con un tipo di dati personalizzatoDeserialize tipo di dati XML personalizzato in C#

<foo> 
    <time type="epoch_seconds">1295027809.26896</time> 
</foo> 

mi piacerebbe avere una classe in grado di convertire automaticamente in Epoch secondi:

[Serializable] 
public class Foo 
{ 
     public Foo() 
     { 
     } 

     public EpochTime Time { get; set; } 
} 

c'è un modo per definire una classe EpochTime in modo che il serializzatore XML sa usarlo quando trovare XML con type="epoch_time"? E se sì, come faccio a impostare il WriteXml e ReadXml per farlo?

+0

('[Serializable]' non influenza la serializzazione xml) –

risposta

4

Il modo normale è quello di shim semplicemente con una proprietà che si comporta come ci si aspetta:

public class EpochTime { 
    public enum TimeType { 
     [XmlEnum("epoch_seconds")] Seconds 
    } 
    [XmlAttribute("type")] public TimeType Type {get;set;} 
    [XmlText] public string Text {get;set;} 

    [XmlIgnore] public DateTime Value { 
     get { /* your parse here */ } 
     set { /* your format here */ } 
    } 
} 

anche, si avrebbe bisogno:

[XmlElement("time")] 
public EpochTime Time { get; set; } 

Ecco un esempio completo con il tuo xml:

using System; 
using System.IO; 
using System.Xml; 
using System.Xml.Serialization; 
static class Program 
{ 
    static void Main() 
    { 
     Foo foo; 
     var ser = new XmlSerializer(typeof(Foo)); 
     using (var reader = XmlReader.Create(new StringReader(@"<foo> 
    <time type=""epoch_seconds"">1295027809.26896</time> 
</foo>"))) 
     { 
      foo = (Foo)ser.Deserialize(reader); 
     } 
    } 
} 
public class EpochTime 
{ 
    public enum TimeType 
    { 
     [XmlEnum("epoch_seconds")] 
     Seconds 
    } 
    [XmlAttribute("type")] 
    public TimeType Type { get; set; } 
    [XmlText] 
    public string Text { get; set; } 
    private static readonly DateTime Epoch = new DateTime(1970, 1, 1); 
    [XmlIgnore] public DateTime Value 
    { 
     get 
     { 
      switch (Type) 
      { 
       case TimeType.Seconds: 
        return Epoch + TimeSpan.FromSeconds(double.Parse(Text)); 
       default: 
        throw new NotSupportedException(); 
      } 
     } 
     set { 
      switch (Type) 
      { 
       case TimeType.Seconds: 
        Text = (value - Epoch).TotalSeconds.ToString(); 
        break; 
       default: 
        throw new NotSupportedException(); 
      } 
     } 
    } 
} 
[XmlRoot("foo")] 
public class Foo 
{ 
    public Foo() 
    { 
    } 

    [XmlElement("time")] 
    public EpochTime Time { get; set; } 
} 
0

Avete davvero bisogno di implementare ISerializable? Quanto segue potrebbe funzionare nello scenario:

public class EpochTime 
{ 
    [XmlText] 
    public double Data { get; set; } 
    [XmlAttribute("type")] 
    public string Type { get; set; } 
} 

public class Foo 
{ 
    public EpochTime Time { get; set; } 
} 

class Program 
{ 
    public static void Main() 
    { 
     var foo = new Foo 
     { 
      Time = new EpochTime 
      { 
       Data = 1295027809.26896, 
       Type = "epoch_seconds" 
      } 
     }; 
     var serializer = new XmlSerializer(foo.GetType()); 
     serializer.Serialize(Console.Out, foo); 
    } 
} 

notare inoltre che [Serializable] non ha alcun effetto sulla XmlSerializer.