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
risposta
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.
Uri strumenti di classe ISerializable Interfaccia in modo che dovrebbe essere in grado di occuparsi della serializzazione/deserializzazione.
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
Vale a dire per la serializzazione * binary *; la domanda (vedi tag) riguarda la serializzazione * xml * –
Uri è già serializzabile, quindi non credo che tu debba fare qualsiasi cosa.
http://msdn.microsoft.com/en-us/library/system.uri(VS.80).aspx
I tag suggeriscono xmlserializer, in modo che (da solo) non faccia molto –
implementare e IDeserializationCallback e l'uso che di campo sul proprio.
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ideserializationcallback.aspx
I tag suggeriscono xmlserializer - che non supporta questi –
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)
Nota: C'è un piccolo intoppo qui. La serializzazione funzionerà, ma la de-serializzazione fallirà. –
@SriwanthaAttanayake Penso che dipenda dall'Uri. – Aelphaeis
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>
I tag suggeriscono XmlSerializer; in realtà, non è necessario [Serializable] per questo - il tipo deve solo essere pubblico. –