Comment sérialiser une propriété de type Object avec XmlSerializer

J’ai une propriété:

public object Tag 

mais il peut contenir un nombre fini de types, malheureusement sans type de base (sauf le type d’object). Mais lorsque je sérialise l’object avec cette propriété, il n’est pas sérialisé. Est-il possible d’instruire XmlSerializer avec les types possibles?

Je ne le recommande pas, mais vous pouvez utiliser [XmlElement] etc., pour le renseigner sur plusieurs types de candidats pour un membre:

 public class Test { private static void Main() { var ser = new XmlSerializer(typeof (Test)); var obj = new Test {Value = "abc"}; ser.Serialize(Console.Out, obj); obj = new Test { Value = 123 }; ser.Serialize(Console.Out, obj); obj = new Test { Value = 456.7F }; ser.Serialize(Console.Out, obj); } [XmlElement("a", Type = typeof(int))] [XmlElement("b", Type = typeof(ssortingng))] [XmlElement("c", Type = typeof(float))] public object Value { get; set; } } 

Les bits importants de la sortie (en ignorant tous les xmlns / etc.) sont les suivants:

  abc   123   456.7  

Je l’ai fait en implémentant l’interface IXmlSerializable , en écrivant le type d’object en tant qu’atsortingbut d’élément.

  public void ReadXml(XmlReader reader) { reader.MoveToContent(); Boolean isEmptyElement = reader.IsEmptyElement; reader.ReadStartElement(); if (!isEmptyElement) { // ...here comes all other properties deserialization object tag; if (ReadXmlObjectProperty(reader, "Tag", out tag)) { Tag = tag; } reader.ReadEndElement(); } } public void WriteXml(XmlWriter writer) { // ...here comes all other properties serialization WriteXmlObjectProperty(writer, "Tag", Tag); } public static bool ReadXmlObjectProperty(XmlReader reader, ssortingng name, out object value) { value = null; // Moves to the element while (!reader.IsStartElement(name)) { return false; } // Get the serialized type ssortingng typeName = reader.GetAtsortingbute("Type"); Boolean isEmptyElement = reader.IsEmptyElement; reader.ReadStartElement(); if (!isEmptyElement) { Type type = Type.GetType(typeName); if (type != null) { // Deserialize it XmlSerializer serializer = new XmlSerializer(type); value = serializer.Deserialize(reader); } else { // Type not found within this namespace: get the raw ssortingng! ssortingng xmlTypeName = typeName.Subssortingng(typeName.LastIndexOf('.')+1); value = reader.ReadElementSsortingng(xmlTypeName); } reader.ReadEndElement(); } return true; } public static void WriteXmlObjectProperty(XmlWriter writer, ssortingng name, object value) { if (value != null) { Type valueType = value.GetType(); writer.WriteStartElement(name); writer.WriteAtsortingbuteSsortingng("Type", valueType.FullName); writer.WriteRaw(ToXmlSsortingng(value, valueType)); writer.WriteFullEndElement(); } } public static ssortingng ToXmlSsortingng(object item, Type type) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = Encoding.ASCII; settings.Indent = true; settings.OmitXmlDeclaration = true; settings.NamespaceHandling = NamespaceHandling.OmitDuplicates; using(SsortingngWriter textWriter = new SsortingngWriter()) using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) { XmlSerializer serializer = new XmlSerializer(type); serializer.Serialize(xmlWriter, item, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })); return textWriter.ToSsortingng(); } } 

Remarque: dans le code, je n’utilise ni espace de nom ni codage ASCII. Ce sont des choix non obligatoires.

HTH, Cabbi

Vous pouvez également utiliser [XmlInclude(typeof(YourType))] sur la classe contenant la propriété de l’object. Donc, dans le cas du PO, cela ressemblerait à ceci

 [XmlInclude(typeof(PossibleClassOne))] [XmlInclude(typeof(PossibleClassTwo))] public class MyClass { public object Tag { get; set; } } 

De cette façon, vous pouvez conserver votre nom d’élément dans tous les cas.