Dot-Net

XmlSerializer 將 xsi:type 替換為節點名稱

  • July 15, 2015

目前 XmlSerializer 產生以下結構:

<config>
 <BaseType xsi:type="DerivedType1" />
 <BaseType xsi:type="DerivedType2" />
</config>

有沒有辦法讓它把類型名稱放入節點:

<config>
 <DerivedType1 />
 <DerivedType2 />
</config>

?

使用XmlElementAttribute建構子重載(string elementName, Type type)。它允許您根據在成員中找到的實際類型替換元素名稱。如果您有多個派生類型,請將其中幾個堆疊在一起。

如果您嘗試序列化List<Base>可能包含 Derived 實例的通用集合,則以XmlArrayItem相同的方式使用。

以這種方式定義也隱式使派生類型已知,因此XmlInclude不需要屬性

樣本定義:

[XmlRoot]
public class Data
{
   [XmlElement("Derived1", typeof(Derived1))]
   [XmlElement("Derived2", typeof(Derived2))]
   public Base foo { get; set; }
   [XmlArrayItem("Derived1", typeof(Derived1))]
   [XmlArrayItem("Derived2", typeof(Derived2))]
   public List<Base> fooList { get; set; }
}

public class Base { ... }
public class Derived1 : Base { ... }
public class Derived2 : Base { ... }

為什麼人們總是說“你永遠無法反序列化”。這絕對是錯誤的。

public class BaseClass {
 public string Name {get;set;}
}
[XmlRoot("BaseClass")]
public class ChildClass : BaseClass {
 public int Value {get;set;}
}
[XmlRoot("BaseClass")]
public class FlatClass
{
 public string Name {get;set;}
 public int Value {get;set;}
}

XmlSerializer ser1 = new XmlSerializer(typeof(BaseClass));
XmlSerializer ser2 = new XmlSerializer(typeof(ChildClass));
XmlSerializer ser3 = new XmlSerializer(typeof(FlatClass));
ser1.Serialize(File.Open("ser1.xml", FileMode.Create), new BaseClass(){Name="Base"});
ser2.Serialize(File.Open("ser2.xml", FileMode.Create), new ChildClass(){Name="Child",Value = 1});

ser1.Deserialize(File.OpenRead("ser2.xml"));
ser2.Deserialize(File.OpenRead("ser1.xml"));
ser3.Deserialize(File.OpenRead("ser2.xml"));

繁榮。工作得很好!!!!序列化在這三個方面都完美無缺。生成的對像在任一側可能都不是 100%,但它確實會反序列化。Ser1 在反序列化 ser2.xml 時忽略 Value 元素 Ser2 在反序列化 ser1.xml 時跳過 Value 屬性

唯一打破這個模型的是:

ser1.Serailize(File.Open("ser3.xml", FileMode.Create), new ChildClass(){Name = "Child2", Value = 2});
XmlSerialize ser3 = new XmlSerializer(typeof(FlatClass));
ser3.Deserialize(File.OpenRead("ser3.xml"));

最後一次中斷,因為 BaseClass 的序列化程序遵循在元素上包含 xsi:type=“ChildClass” 屬性的模式標準(儘管這是一個有價值的和 99% 的時間標準)。Ser3 無法處理該類型,因為它與該類型無關,特別是如果 FlatClass 存在於跨 WAN 或 LAN 線路的另一個程序集中。就像 Honey-badger 一樣,XmlSerailizer 不關心元素或值,只要它可以找到它們並且架構中的任何內容都不會破壞該過程。XSI:TYPE 屬性會破壞模式。

例如,當使用 WCF 或其他基於 XML 通信的系統時,如果服務有一個名為 FlatClass 的類,它不會反序列化包含 xsi:type="" 屬性的 ChildClass。但是,如果您不使用 BaseClass 的序列化程序,它將反序列化完全相同的 XML 而沒有該 xsi:type 屬性。

QED包括 xsi:type 屬性通常是有益的、必要的和可取的。

話雖如此,有沒有辦法為 BaseClass 類型創建一個 XmlSerializer 並告訴它在序列化子類型時不要包含 xsi:type 屬性?

感謝 Jaeden “Sifo Dyas” al’Raec Ruiner

引用自:https://stackoverflow.com/questions/9359979