XmlSerializer заменяет xsi: тип для имени узла - PullRequest
9 голосов
/ 20 февраля 2012

В настоящее время XmlSerializer создает следующую структуру:

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

Есть ли способ сделать так, чтобы имя типа помещалось в узел:

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

Ответы [ 3 ]

26 голосов
/ 29 ноября 2012

Использовать перегрузку конструктора 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 { ... }
1 голос
/ 16 июля 2015

Почему люди продолжают говорить: «Вы никогда не сможете десериализоваться». Это определенно ЛОЖЬ.

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"));

Boom. Работает просто отлично !!!!! Сериализация идеально подходит для всех трех направлений. результирующие объекты не могут быть на 100% с обеих сторон, но это ДЕСЕРАЛИЗИРУЕТ. Ser1 игнорирует элемент Value при десериализации ser2.xml Ser2 пропускает значение свойства при десериализации ser1.xml

Единственное, что ломает эту модель:

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 следует стандарту схемы (хотя это ценный и 99% требуемый стандарт времени) включения атрибута xsi: type = "ChildClass" в элемент. Ser3 не может обработать этот тип, потому что он не соответствует этому типу, особенно если FlatClass существует в другой сборке через линии WAN или LAN. Так же, как медовый барсук, XmlSerailizer не заботится об элементах или значениях, пока он не может их найти, и ничто в схеме не нарушает процесс. Атрибут XSI: TYPE нарушает схему.

Как, например, при использовании WCF или других систем, основанных на XML-коммуникациях, если у Сервиса есть класс с именем FlatClass, он НЕ ОБЕСПЕЧИВАЕТ дочерний класс, содержащий атрибут xsi: type = "". Однако, если вы не используете сериализатор для BaseClass, он БЕЗ десериализует тот же XML без этого атрибута xsi: type.

Q.E.D. Часто бывает полезно, необходимо и желательно, чтобы НЕ включал атрибут xsi: type.

Итак, с учетом сказанного, есть ли способ создать XmlSerializer для типа BaseClass и запретить ему включать атрибут xsi: type при сериализации дочернего типа?

Спасибо Jaeden "Sifo Dyas" al'Raec Ruiner

0 голосов
/ 20 февраля 2012

Что ж, вы можете просто переопределить имя элемента с помощью атрибута XmlElement, например,

[XmlElement("DerivedType1")]
public BaseType : DerivedType1 {get;set;}

, если все равно добавит xsi: type, и создаст еще большую путаницу ...

Как выглядит ваш класс?

...