Есть ли причина, почему базовый класс, украшенный XmlInclude, по-прежнему будет генерировать неизвестное значение типа при сериализации?
Я упрощу код, чтобы сэкономить место, но представленное иллюстрирует основную проблему.
У меня есть класс, который имеет свойство, которое является базовым типом. Существует 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 (String n, String ns, PaymentSummary o, Boolean isNullable, Boolean needType) в
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPaymentSummaryRequest.Write14_PaymentSummaryRequest (String n, String ns, PaymentSummaryRequest o, Boolean isNullable, Boolean needType) в
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterPaymentSummaryRequest.Write15_TRANSACTION (Объект o) --- Конец внутреннего стека исключений trace --- at
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
Ответы
Ответ 1
Проблема, которую вы видите, связана с тем, что PaymentSummaryRequest
устанавливает пространство имен. Вы можете либо удалить пространство имен, либо добавить пространство имен в класс PaymentSummary
:
[XmlRoot(Namespace = Constants.Namespace)]
[XmlInclude(typeof(xxxPaymentSummary))]
public abstract class PaymentSummary
{
}
Как отмечает @Tedford в своем комментарии ниже, пространство имен требуется только при использовании производных типов.
Похоже, что при создании сборки XML Serialization, поскольку Root node имеет пространство имен и базовый класс не включает в себя логику XML Include в сгенерированной сборке сериализации.
Другим подходом к решению проблемы будет удаление деклараций пространства имен из самих классов и определение пространства имен в конструкторе XmlSerializer
:
var serializer = new XmlSerializer(
typeof(PaymentSummaryRequest),
Constants.Namespace
);
Ответ 2
У меня была та же проблема, и некоторые из Google привели меня сюда. Я не мог принять наличие атрибута XMLInclude
для каждой реализации в базовом классе. Я получил его для работы с общим методом сериализации. Прежде всего, некоторые из оригинального примера OP, но немного модифицированные для ясности:
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]()