2012-02-29 104 views
6

我有一个属性:如何序列类型对象的属性与XmlSerializer的

public object Tag 

但它可以包含有限数量的类型,不幸的是无碱基类型(除对象类型)。但是当我用这个属性序列化对象时,它不会被序列化。有没有办法指示XmlSerializer可能的类型?

+0

我期望你可以实现了ISerializable和控制的序列化对象取决于标签的类型,将其转换为可序列化的类型。但是我不知道你以后如何反序列化对象。序列化对象类型的东西可能不是一个好主意。 – 2012-02-29 10:31:15

+1

@Adrian'XmlSerializer'不关心'ISerializable';然而,我同意坦率地说,这种情况最好简单地避免 – 2012-02-29 10:33:05

+0

@Marc XmlSerializer并不关心ISerialiable,但它确实关心IXmlSerializable,并且会在实现它的对象上调用读写方法。 – Fen 2012-02-29 11:18:07

回答

9

我并不推荐这样做,但是,是的,你可以使用[XmlElement]等来告诉它的多个候选类型的成员:

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(string))] 
    [XmlElement("c", Type = typeof(float))] 
    public object Value { get; set; } 
} 

输出的重要位(忽略所有xmlns/<?xml>等)为:

<Test> 
    <b>abc</b> 
</Test> 

<Test> 
    <a>123</a> 
</Test> 

<Test> 
    <c>456.7</c> 
</Test> 
+0

完美的作品! – user919426 2015-03-23 09:36:44

+0

只有对元素使用不同的名称或名称空间时,这才有效(本例中为a,b,c)。就我而言,我需要元素名称始终相同,所以我发布了一个似乎适用于我的答案。 – Evan 2017-04-07 20:08:34

0

我做到了实现IXmlSerializable接口,写对象类型作为元素属性。

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, 
              string name, 
              out object value) 
    { 
    value = null; 

    // Moves to the element 
    while (!reader.IsStartElement(name)) 
    { 
     return false; 
    } 
    // Get the serialized type 
    string typeName = reader.GetAttribute("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 string! 
      string xmlTypeName = typeName.Substring(typeName.LastIndexOf('.')+1); 
      value = reader.ReadElementString(xmlTypeName); 
     } 
     reader.ReadEndElement(); 
    } 

    return true; 
    } 
    public static void WriteXmlObjectProperty(XmlWriter writer, 
              string name, 
              object value) 
    { 
    if (value != null) 
    { 
     Type valueType = value.GetType(); 
     writer.WriteStartElement(name); 
     writer.WriteAttributeString("Type", valueType.FullName); 
     writer.WriteRaw(ToXmlString(value, valueType)); 
     writer.WriteFullEndElement(); 
    } 
    } 

    public static string ToXmlString(object item, Type type) 
    { 
    XmlWriterSettings settings = new XmlWriterSettings(); 
    settings.Encoding = Encoding.ASCII; 
    settings.Indent = true; 
    settings.OmitXmlDeclaration = true; 
    settings.NamespaceHandling = NamespaceHandling.OmitDuplicates; 

    using(StringWriter textWriter = new StringWriter()) 
    using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) 
    { 
     XmlSerializer serializer = new XmlSerializer(type); 
     serializer.Serialize(xmlWriter, item, new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty })); 
     return textWriter.ToString(); 
    } 
    } 

注意:在代码中我没有使用命名空间和ASCII编码,这些都是非强制选择。

HTH, Cabbi

0

您还可以在的类,它包含的对象属性使用[XmlInclude(typeof(YourType))]。因此,在OP的情况下,它看起来像这样

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

这样,您就可以保持你的元素名称<Tag>在所有情况下

相关问题