2009-06-24 7 views
16

J'ai une classe que j'ai marquée Serializable, avec une propriété Uri. Comment puis-je obtenir l'Uri sérialiser/désérialiser sans faire la propriété de type chaîne?Comment (xml) sérialiser un uri

+1

Les balises suggèrent XmlSerializer; en fait, vous n'avez pas besoin de [Serializable] pour cela - le type doit simplement être public. –

Répondre

12

Basé sur l'une des réponses pour how to serialize TimeSpan J'ai fini avec ce qui fonctionne très bien pour moi et ne nécessite pas la propriété supplémentaire :

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

Ensuite, vous pouvez l'utiliser comme ceci

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

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

et ce sera bien sérialisation et la désérialisation.

Remarque: Impossible d'utiliser l'astuce avec l'attribut XmlElement(Type = typeof(...)) comme indiqué dans une autre réponse dans la question ci-dessus liée car le XmlSerializer vérifie un constructeur par défaut vide d'abord sur le type d'origine.

0

Uri classe implémente ISerializable Interface de sorte qu'il devrait être en mesure de prendre soin de la sérialisation/désérialisation.

+0

Hmmm, peut-être une chose de 3,5? J'obtiens une exception qu'il n'y a pas de constructeur par défaut quand je sérialise en 2.0 – Jeremy

+4

C'est pour la sérialisation * binaire *; la question (voir tags) est sur * xml * sérialisation –

32

Avec xml sérialiseur, vous êtes limité - il est aussi polyvalent que (par exemple) certains des BinaryFormatter/ISerializable options. Une astuce fréquente est d'avoir une seconde propriété pour la sérialisation:

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

Les deux attributs explorables cachent la vue (mais il doit être sur l'API publique pour XmlSerializer l'utiliser). Le XmlIgnore lui dit de ne pas essayer le Uri; et le [XmlAttribute(...)] (ou [XmlElement(...)]) lui dit de renommer UriString lors de (dé) sérialiser.

(notez que EditorBrowsable applique uniquement au code extérieur de l'ensemble déclarant le type)

+0

Note: Il y a un petit accroc ici. La sérialisation fonctionnera, mais la désérialisation échouera. –

+0

@SriwanthaAttanayake Je pense que cela dépend de l'Uri. – Aelphaeis

1

Pour ceux qui ont trouvé cette question et qui n'ont pas aimé les solutions, il existe une autre solution plus flexible et plus puissante. C'est l'interface IXmlSerializable d'exécution. C'est plus difficile, mais ça vaut le coup. Vous pouvez créer n'importe quel fichier XML que vous souhaitez. L'exemple est simple:

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

Et vous obtenez quelque chose comme ça dans xml:

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