XmlSerializer - была ошибка, отражающая тип
Используя С#.NET 2.0, у меня есть составной класс данных, у которого есть атрибут [Serializable]
. Я создаю класс XMLSerializer
и передаю его в конструктор:
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
Я получаю исключение:
Произошла ошибка, отражающая тип.
Внутри класса данных есть еще один составной объект. Должен ли это также иметь атрибут [Serializable]
или его наличие на верхнем объекте, он рекурсивно применяет его ко всем объектам внутри?
Ответы
Ответ 1
Посмотрите на внутреннее исключение, которое вы получаете. Он расскажет вам, какое поле/свойство имеет проблемы с сериализацией.
Вы можете исключить поля/свойства из сериализации XML, украсив их атрибутом [XmlIgnore]
.
Я не думаю, что XmlSerializer
использует атрибут [Serializable]
, поэтому я сомневаюсь, что это проблема.
Ответ 2
Помните, что сериализованные классы должны иметь конструкторы по умолчанию (то есть без параметров). Если у вас нет никакого конструктора, это прекрасно; но если у вас есть конструктор с параметром, вам также нужно добавить значение по умолчанию.
Ответ 3
У меня была аналогичная проблема, и оказалось, что сериализатор не может отличить 2 класса, которые я имел с тем же именем (один из них был подклассом другого). Внутреннее исключение выглядело следующим образом:
'Типы BaseNamespace.Class1' и 'BaseNamespace.SubNamespace.Class1' используют имя типа XML, 'Class1', из пространства имен ''. Используйте атрибуты XML, чтобы указать уникальное имя XML и/или пространство имен для типа.
Где BaseNamespace.SubNamespace.Class1 является подклассом BaseNamespace.Class1.
Мне нужно было добавить атрибут к одному из классов (я добавил в базовый класс):
[XmlType("BaseNamespace.Class1")]
Примечание. Если у вас больше слоев классов, вам также нужно добавить к ним атрибут.
Ответ 4
Также имейте в виду, что XmlSerializer
не может сериализовать абстрактные свойства. См. мой вопрос здесь (к которому я добавил код решения).
Сериализация XML и унаследованные типы
Ответ 5
Все объекты в графе сериализации должны быть сериализованы.
Так как XMLSerializer
является черным ящиком, проверьте эти ссылки, если вы хотите отлаживать дальше процесс сериализации.
Изменение, где XmlSerializer выводит временные сборки
КАК: Отлаживать сборку .NET XmlSerializer
Ответ 6
Я обнаружил, что класс Dictionary в .Net 2.0 не сериализуется с использованием XML, но сериализуется хорошо, когда используется двоичная сериализация.
Я нашел работу здесь.
Ответ 7
Если вам нужно обрабатывать определенные атрибуты (например, словарь или любой класс), вы можете реализовать интерфейс IXmlSerialiable, который позволит вам больше свободы за счет более подробного кодирования.
public class NetService : IXmlSerializable
{
#region Data
public string Identifier = String.Empty;
public string Name = String.Empty;
public IPAddress Address = IPAddress.None;
public int Port = 7777;
#endregion
#region IXmlSerializable Implementation
public XmlSchema GetSchema() { return (null); }
public void ReadXml(XmlReader reader)
{
// Attributes
Identifier = reader[XML_IDENTIFIER];
if (Int32.TryParse(reader[XML_NETWORK_PORT], out Port) == false)
throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_PORT);
if (IPAddress.TryParse(reader[XML_NETWORK_ADDR], out Address) == false)
throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_ADDR);
}
public void WriteXml(XmlWriter writer)
{
// Attributes
writer.WriteAttributeString(XML_IDENTIFIER, Identifier);
writer.WriteAttributeString(XML_NETWORK_ADDR, Address.ToString());
writer.WriteAttributeString(XML_NETWORK_PORT, Port.ToString());
}
private const string XML_IDENTIFIER = "Id";
private const string XML_NETWORK_ADDR = "Address";
private const string XML_NETWORK_PORT = "Port";
#endregion
}
Есть интересная статья которая демонстрирует элегантный способ реализовать сложный способ "расширить" XmlSerializer.
В статье говорится:
IXmlSerializable содержится в официальной документации, но в документации говорится, что он не предназначен для общего пользования и не содержит никакой информации, кроме этого. Это указывает на то, что команда разработчиков хотела зарезервировать право изменять, отключать или даже полностью удалять этот способ расширения с помощью дороги. Однако, пока вы готовы принять эту неопределенность и решить возможные изменения в будущем, нет никакой причины, по которой вы не можете ее использовать.
Поэтому я предлагаю реализовать собственные классы IXmlSerializable
, чтобы избежать слишком сложной реализации.
... с помощью отражения может быть просто реализовать наш пользовательский класс XmlSerializer
.
Ответ 8
Наиболее распространенные причины для меня:
- the object being serialized has no parameterless constructor
- the object contains Dictionary
- the object has some public Interface members
Ответ 9
Недавно я получил это в частичном классе веб-ссылки при добавлении нового свойства. Класс, созданный автоматически, добавлял следующие атрибуты.
[System.Xml.Serialization.XmlElementAttribute(Order = XX)]
Мне нужно было добавить аналогичный атрибут с порядком выше предыдущего в автоматически сгенерированной последовательности, и это исправило это для меня.
Ответ 10
Я тоже думал, что атрибут Serializable должен быть на объекте, но если я не являюсь полным noob (я нахожусь в середине сеанса ночного кодирования), следующие работы из SnippetCompiler:
using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Xml.Serialization;
public class Inner
{
private string _AnotherStringProperty;
public string AnotherStringProperty
{
get { return _AnotherStringProperty; }
set { _AnotherStringProperty = value; }
}
}
public class DataClass
{
private string _StringProperty;
public string StringProperty
{
get { return _StringProperty; }
set{ _StringProperty = value; }
}
private Inner _InnerObject;
public Inner InnerObject
{
get { return _InnerObject; }
set { _InnerObject = value; }
}
}
public class MyClass
{
public static void Main()
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
TextWriter writer = new StreamWriter(@"c:\tmp\dataClass.xml");
DataClass clazz = new DataClass();
Inner inner = new Inner();
inner.AnotherStringProperty = "Foo2";
clazz.InnerObject = inner;
clazz.StringProperty = "foo";
serializer.Serialize(writer, clazz);
}
finally
{
Console.Write("Press any key to continue...");
Console.ReadKey();
}
}
}
Я бы предположил, что XmlSerializer использует отражение над публичными свойствами.
Ответ 11
Я получил ту же ошибку и обнаружил, что проблема с типом IEnumerable<SomeClass>
была проблемой. Похоже, что IEnumerable
не может быть сериализовано напрямую.
Ответ 12
У меня была ситуация, когда порядок был одинаковым для двух элементов в строке
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]
.... некоторый код...
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]
Когда я изменил код, чтобы увеличить порядок на один для каждого нового свойства в классе, ошибка исчезла.
Ответ 13
Также обратите внимание, что вы не можете сериализовать элементы управления пользовательским интерфейсом и что любой объект, который вы хотите передать в буфер обмена, должен быть сериализуемым, иначе он не может быть передан другим процессам.
Ответ 14
Я использую класс NetDataSerialiser
для сериализации
мои классы домена. класс NetDataContractSerializer.
Классы домена совместно используются клиентом и сервером.
Ответ 15
[System.Xml.Serialization.XmlElementAttribute( "strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
//Или
[XmlIgnore]
string [] strFielsName {get; set;}
Ответ 16
У меня была такая же проблема, и в моем случае у объекта был ReadOnlyCollection. Коллекция должна реализовать метод Add для сериализации.