Есть ли причина, по которой базовый класс, оформленный с помощью XmlInclude, по-прежнему генерирует исключение типа неизвестно при сериализации? - PullRequest
42 голосов
/ 06 января 2011

Я упросту код для экономии места, но то, что представлено, иллюстрирует основную проблему.

У меня есть класс, у которого есть свойство, являющееся базовым типом.Есть 3 производных класса, которые могут быть назначены этому свойству.

Если я назначу какой-либо из производных классов контейнеру и попытаюсь сериализовать контейнер, XmlSerializer выдает ужас:

"Тип x не ожидался. Используйте XmlIncludeили атрибут SoapInclude для указания типов, которые статически не известны. "

Однако мой базовый класс уже украшен этим атрибутом, поэтому я считаю, что должно быть дополнительное «скрытое» требование.

Действительно странная часть заключается в том, что сериализатор WCF по умолчанию не имеетпроблемы с этой иерархией классов.

Класс-контейнер

[DataContract]
[XmlRoot(ElementName = "TRANSACTION", Namespace = Constants.Namespace)]
public class PaymentSummaryRequest : CommandRequest
{
    [DataMember]
    public PaymentSummary Summary { get; set; }

    public PaymentSummaryRequest()
    {
        Mechanism = CommandMechanism.PaymentSummary;
    }
}

Базовый класс

[DataContract]
[XmlInclude(typeof(xPaymentSummary))]
[XmlInclude(typeof(yPaymentSummary))]
[XmlInclude(typeof(zPaymentSummary))]
[KnownType(typeof(xPaymentSummary))]
[KnownType(typeof(yPaymentSummary))]
[KnownType(typeof(zPaymentSummary))]
public abstract class PaymentSummary
{     
}

Один из производных классов

[DataContract]
public class xPaymentSummary : PaymentSummary
{
}

Код сериализации

var serializer = new XmlSerializer(typeof(PaymentSummaryRequest));
serializer.Serialize(Console.Out,new PaymentSummaryRequest{Summary = new xPaymentSummary{}});

Исключение

System.InvalidOperationException: при создании XML-документа произошла ошибка.---> System.InvalidOperationException: тип xPaymentSummary не ожидался.Используйте атрибут XmlInclude или SoapInclude, чтобы указать типы, которые не известны статически.в

Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPaymentSummaryRequest.Write13_PaymentSummary (Строка n, Строка ns, PaymentSummary o, логическое значение isNullable, логическое значение needType) в

*..Serialization.GeneratedAssembly.XmlSerializationWriterPaymentSummaryRequest.Write14_PaymentSummaryRequest (Строка n, Строка ns, PaymentSummaryRequest o, логическое значение isNullable, логическое значение needType) в

WareSense_Rechange.Exchange.Exchange.Exchange.Exchange.Exchange_Exchange.Exchange_Exchange_Exchange.Extification.- Конец внутренней трассировки стека исключений --- в

System.Xml.Serialization.XmlSerializer.Serialize (XmlWriter xmlWriter, Object o, XmlSerializerNamespaces пространства имен, String encodingStyle, String id) в

System.Xml.Serialization.XmlSerializer.Serialize (TextWriter textWriter, Object o, пространства имен XmlSerializerNamespaces)
в UserQuery.RunUserAuthoredQuery () в c: \ Users \ Tedford \ AppData \ Local \ Temp \ uqacncyo.0.cs: строка 47

Ответы [ 2 ]

40 голосов
/ 06 января 2011

Проблема, которую вы видите, заключается в том, что PaymentSummaryRequest задает пространство имен.Вы можете удалить пространство имен или добавить пространство имен к классу PaymentSummary:

[XmlRoot(Namespace = Constants.Namespace)]
[XmlInclude(typeof(xxxPaymentSummary))]
public abstract class PaymentSummary
{
}

Как @Tedford упоминает в своем комментарии ниже пространства имен, требуется только при использовании производных типов.

При создании сборки XML-сериализации выглядит так, что поскольку корневому узлу задано пространство имен, а базовый класс этого не делает, он не включает логику включения XML в созданную сборку сериализации.

Другой подход к решению этой проблемы - удалить объявления пространства имен из самих классов и указать пространство имен в конструкторе XmlSerializer:

var serializer = new XmlSerializer(
    typeof(PaymentSummaryRequest), 
    Constants.Namespace
);
0 голосов
/ 11 июня 2019

У меня была та же проблема, и некоторые из Google привели меня сюда. Я не мог принять наличие атрибута XMLInclude для каждой реализации в базовом классе. Я получил его для работы с общим методом сериализации. Во-первых, некоторые из оригинального примера ОП, но немного доработанные для ясности:

public abstract class PaymentSummary
{
  public string _summary;
  public string _type;
}

public class xPaymentSummary : PaymentSummary
{
  public xPaymentSummary() { }

  public xPaymentSummary(string summary)
  {
     _summary = summary;
     _type = this.GetType().ToString();
  }
}

В дополнение к вышесказанному существуют также yPaymentSummary и zPaymentSummary с точно такой же реализацией. Они добавляются в коллекцию, и затем метод сериализации может быть вызван для каждого:

List<PaymentSummary> summaries = new List<PaymentSummary>();
summaries.Add(new xPaymentSummary("My summary is X."));
summaries.Add(new yPaymentSummary("My summary is Y."));
summaries.Add(new zPaymentSummary("My summary is Z."));

foreach (PaymentSummary sum in summaries)
  SerializeRecord(sum);

Наконец, метод сериализации - простой универсальный метод, который использует тип записи при сериализации:

static void SerializeRecord<T>(T record) where T: PaymentSummary
{
  var serializer = new XmlSerializer(record.GetType());
  serializer.Serialize(Console.Out, record);

  Console.WriteLine(" ");
  Console.WriteLine(" ");
}

Выше приведено следующее:

enter image description here

...