2012-02-29 103 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>在所有情況下

相關問題