2009-06-24 15 views
16

Ho una classe che ho contrassegnato come Serializable, con una proprietà Uri. Come posso far sì che l'URI esegua la serializzazione/deserializzazione senza rendere la proprietà di tipo stringa?Come (xml) serializzare un uri

+1

I tag suggeriscono XmlSerializer; in realtà, non è necessario [Serializable] per questo - il tipo deve solo essere pubblico. –

risposta

12

Sulla base di una delle risposte per how to serialize TimeSpan ho finito con questo, che funziona abbastanza bene per me e non richiede la proprietà aggiuntiva :

public class XmlUri : IXmlSerializable 
{ 
    private Uri _Value; 

    public XmlUri() { } 
    public XmlUri(Uri source) { _Value = source; } 

    public static implicit operator Uri(XmlUri o) 
    { 
     return o == null ? null : o._Value; 
    } 

    public static implicit operator XmlUri(Uri o) 
    { 
     return o == null ? null : new XmlUri(o); 
    } 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     _Value = new Uri(reader.ReadElementContentAsString()); 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     writer.WriteValue(_Value.ToString()); 
    } 
} 

quindi è possibile utilizzare in questo modo

public class Settings 
{ 
    public XmlUri Uri { get; set; } 
} 

... 
var s = new Settings { Uri = new Uri("http://www.example.com") }; 

e sarà ben serializzare e deserializzare.

Nota: Non è possibile utilizzare il trucco con l'attributo XmlElement(Type = typeof(...)) come indicato in un'altra risposta alla domanda di cui sopra collegata come le XmlSerializer controlli per un costruttore di default vuota prima sul tipo di originale.

0

Uri strumenti di classe ISerializable Interfaccia in modo che dovrebbe essere in grado di occuparsi della serializzazione/deserializzazione.

+0

Hmmm, forse una cosa di 3.5? Ottengo un'eccezione sul fatto che non esiste un costruttore predefinito quando eseguo la serializzazione in 2.0 – Jeremy

+4

Vale a dire per la serializzazione * binary *; la domanda (vedi tag) riguarda la serializzazione * xml * –

32

Con XML serializzatore, si sono limitati - non è così versatile come (ad esempio) alcuni dei BinaryFormatter/ISerializable opzioni. Un trucco frequente è quello di avere una seconda proprietà per la serializzazione:

[XmlIgnore] 
public Uri Uri {get;set;} 

[XmlAttribute("uri")] 
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
public string UriString { 
    get {return Uri == null ? null : Uri.ToString();} 
    set {Uri = value == null ? null : new Uri(value);} 
} 

I due attributi navigabili nascondono alla vista (ma ha bisogno di essere sul API pubblica per XmlSerializer di usarlo). Il XmlIgnore dice di non provare il Uri; e il [XmlAttribute(...)] (o [XmlElement(...)]) dice di rinominare UriString quando (de) serializzarlo.

(si noti che EditorBrowsable si applica solo al codice esterno al gruppo di dichiarare il tipo)

+0

Nota: C'è un piccolo intoppo qui. La serializzazione funzionerà, ma la de-serializzazione fallirà. –

+0

@SriwanthaAttanayake Penso che dipenda dall'Uri. – Aelphaeis

1

Per gli altri che hanno trovato questa domanda e chi non ha gradito le soluzioni, c'è un'altra soluzione più flessibile e potente. È l'interfaccia di implementazione IXmlSerializable. Questo è più difficile, ma ne vale la pena. Puoi creare qualsiasi xml che desideri. L'esempio più semplice è:

public class Product : IXmlSerializable 
{ 
    public string Code { get; set; } 

    public string Model { get; set; } 

    public string Name { get; set; } 

    public Uri ImageUri { get; set; } 

    public virtual System.Xml.Schema.XmlSchema GetSchema() 
    { 
     throw new NotImplementedException(); 
    } 

    public virtual void ReadXml(XmlReader reader) 
    { 
     reader.MoveToContent(); 
     Code = reader.GetAttribute("Code"); 
     Model = reader.GetAttribute("Model"); 
     Name = reader.GetAttribute("Name"); 
     if (reader.ReadToDescendant("Image") && reader.HasAttributes) 
      ImageUri = new Uri(reader.GetAttribute("Src")); 
    } 

    public virtual void WriteXml(XmlWriter writer) 
    { 
     writer.WriteAttributeString("Code", Code); 
     writer.WriteAttributeString("Model", Model); 
     writer.WriteAttributeString("Name", Name); 
     if (ImageUri != null) 
     { 
      writer.WriteStartElement("Image"); 
      writer.WriteAttributeString("Src", ImageUri.AbsoluteUri); 
      writer.WriteEndElement(); 
     } 
    } 
} 

e si ottiene qualcosa di simile in xml:

<PriceContainer Code="314" Model="PP500" Name="NuTone PurePower PP500 Power Unit"> 
    <Image Src="http://www.thinkvacuums.com/images/nutone-pp500-activac.jpg" /> 
</PriceContainer> 
Problemi correlati