2012-07-24 3 views
7

je mets en œuvre IXmlSerializable pour le type ci-dessous qui code pour une valeur de couleur RVB comme une seule chaîne:Comment utiliser un IXmlSerializable personnalisé en tant que XmlAttribute?

public class SerializableColor : IXmlSerializable 
{ 
    public int R { get; set; } 
    public int G { get; set; } 
    public int B { get; set; } 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     var data = reader.ReadString(); 
     reader.ReadEndElement(); 
     var split = data.Split(' '); 
     R = int.Parse(split[0]); 
     G = int.Parse(split[1]); 
     B = int.Parse(split[2]); 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     writer.WriteString(R + " " + G + " " + B); 
    } 
} 

Comme il est une seule chaîne, je voulais l'enregistrer comme un attribut pour économiser l'espace. Mais dès que j'ajouter le [XmlAttribute] à ma propriété, je reçois l'exception suivante: { «. Impossible de sérialiser membre « Couleur » de type SerializableColor XmlAttribute/XmlText ne peut pas être utilisé pour coder les types d'application IXmlSerializable »}

Existe-t-il un moyen de le faire fonctionner comme un attribut?

Répondre

4

L'erreur signifie exactement ce qu'elle dit. Vous ne pouvez pas utiliser ces attributs de sérialisation XML lorsque IXmlSerializable est implémenté car IXmlSerializable s'attend à ce que la sérialisation XML soit entièrement personnalisée. Vous pouvez le faire si vous voulez rendre la classe sérialisable avec XmlSerializer en utilisant les attributs.

[XmlRoot("SerializableColor")] 
public class SerializableColor 
{ 
    [XmlAttribute("R")] 
    public int R { get; set; } 
    [XmlAttribute("G")] 
    public int R { get; set; } 
    [XmlAttribute("B")] 
    public int B { get; set; }  
} 

Aussi, pour votre mise en œuvre de XmlSerializable:

public void ReadXml(XmlReader reader) 
    { 
     string data = null; 

     reader.MoveToAttribute("Color"); 
     if (reader.ReadAttributeValue()) 
     { 
      data = reader.Value; 
     } 
     reader.ReadEndElement(); 

     var split = data.Split(' '); 
     R = int.Parse(split[0]); 
     G = int.Parse(split[1]); 
     B = int.Parse(split[2]); 
    } 

    public void WriteXml(XmlWriter writer) 
    { 
     writer.WriteAttributeString("Color", R + " " + G + " " + B); 
    } 

Si, d'autre part, tout ce que vous cherchez à être en mesure de faire est d'avoir une courte chaîne represenation d'une couleur qui est réversible , jetez un oeil à la ColorTranslator Class. En particulier, voir les méthodes FromHtml et ToHtml.

+0

Nous vous remercions de votre réponse. J'ai deux questions cependant. Premièrement, comment l'implémentation n'est-elle pas correcte? Ressemble assez à l'exemple donné [dans la documentation] (http://msdn.microsoft.com/fr-fr/library/system.xml.serialization.ixmlserializable.aspx) (avec l'avenant décrit dans la section des commentaires). Et deuxièmement, l'attribut XmlRoot est-il pertinent dans l'exemple? Quelles différences cela fait-il? –

+0

En ce qui concerne l'implémentation ne produisant pas de code XML correct, j'avais oublié que "Le framework écrit un élément wrapper et positionne le writer XML après son démarrage". Je vais réviser la réponse. Vous pouvez réellement laisser XmlRoot comme il peut être déduit par XmlSerializer, cependant, lorsque je remplace le comportement de sérialisation par défaut d'une classe, je le fais généralement sur tous les composants pour plus de clarté. – JamieSee

+0

J'ai voté parce que OP demande à qui créer un attribut XML personnalisable. Ne produisant pas d'élément XML. –

6

Malheureusement (& étrangement) il est impossible selon ce lien http://connect.microsoft.com/VisualStudio/feedback/details/277641/xmlattribute-xmltext-cannot-be-used-to-encode-types-implementing-ixmlserializable

Pour autour du problème, je suis actuellement en utilisant l'attribut XmlIgnore pour cacher la propriété complexe et l'exposer comme une chaîne par une autre propriété

public class MyDto 
{ 
    [XmlAttribute(AttributeName = "complex-attribute")] 
    public string MyComplexPropertyAsString 
    { 
     get { return MyComplexMember.ToString(); } 
     set { MyComplexMember.LoadFromString(value); } 
    } 
    [XmlIgnore] 
    public MyComplexMember At { get; set; } 
} 
Questions connexes