Используя С#.NET 2.0, у меня есть составной класс данных, у которого есть атрибут [Serializable]
. Я создаю класс XMLSerializer
и передаю его в конструктор:
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
Я получаю исключение:
Произошла ошибка, отражающая тип.
Внутри класса данных есть еще один составной объект. Должен ли это также иметь атрибут [Serializable]
или его наличие на верхнем объекте, он рекурсивно применяет его ко всем объектам внутри?
Посмотрите на внутреннее исключение, которое вы получаете. Он расскажет вам, какое поле/свойство имеет проблемы с сериализацией.
Вы можете исключить поля/свойства из сериализации XML, украсив их атрибутом [XmlIgnore]
.
Я не думаю, что XmlSerializer
использует атрибут [Serializable]
, поэтому я сомневаюсь, что это проблема.
Помните, что сериализованные классы должны иметь конструкторы по умолчанию (то есть без параметров). Если у вас нет никакого конструктора, это прекрасно; но если у вас есть конструктор с параметром, вам также нужно добавить значение по умолчанию.
У меня была аналогичная проблема, и оказалось, что сериализатор не может отличить 2 класса, которые я имел с тем же именем (один из них был подклассом другого). Внутреннее исключение выглядело следующим образом:
'Типы BaseNamespace.Class1' и 'BaseNamespace.SubNamespace.Class1' используют имя типа XML, 'Class1', из пространства имен ''. Используйте атрибуты XML, чтобы указать уникальное имя XML и/или пространство имен для типа.
Где BaseNamespace.SubNamespace.Class1 является подклассом BaseNamespace.Class1.
Мне нужно было добавить атрибут к одному из классов (я добавил в базовый класс):
[XmlType("BaseNamespace.Class1")]
Примечание. Если у вас больше слоев классов, вам также нужно добавить к ним атрибут.
Также имейте в виду, что XmlSerializer
не может сериализовать абстрактные свойства. См. мой вопрос здесь (к которому я добавил код решения).
Все объекты в графе сериализации должны быть сериализованы.
Так как XMLSerializer
является черным ящиком, проверьте эти ссылки, если вы хотите отлаживать дальше процесс сериализации.
Наиболее распространенные причины для меня:
- the object being serialized has no parameterless constructor
- the object contains Dictionary
- the object has some public Interface members
Если вам нужно обрабатывать определенные атрибуты (например, словарь или любой класс), вы можете реализовать интерфейс 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
.
Я обнаружил, что класс Dictionary в .Net 2.0 не сериализуется с использованием XML, но сериализуется хорошо, когда используется двоичная сериализация.
Я нашел работу здесь.
Недавно я получил это в частичном классе веб-ссылки при добавлении нового свойства. Класс, созданный автоматически, добавлял следующие атрибуты.
[System.Xml.Serialization.XmlElementAttribute(Order = XX)]
Мне нужно было добавить аналогичный атрибут с порядком выше предыдущего в автоматически сгенерированной последовательности, и это исправило это для меня.
Я тоже думал, что атрибут 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 использует отражение над публичными свойствами.
У меня была ситуация, когда порядок был одинаковым для двух элементов в строке
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]
.... некоторый код...
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]
Когда я изменил код, чтобы увеличить порядок на один для каждого нового свойства в классе, ошибка исчезла.
Я получил ту же ошибку и обнаружил, что проблема с типом IEnumerable<SomeClass>
была проблемой. Похоже, что IEnumerable
не может быть сериализовано напрямую.
У меня была такая же проблема, и в моем случае у объекта был ReadOnlyCollection. Коллекция должна реализовать метод Add для сериализации.
[System.Xml.Serialization.XmlElementAttribute( "strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
//Или
[XmlIgnore] string [] strFielsName {get; set;}
Я использую класс NetDataSerialiser
для сериализации
мои классы домена. класс NetDataContractSerializer.
Классы домена совместно используются клиентом и сервером.
Также обратите внимание, что вы не можете сериализовать элементы управления пользовательским интерфейсом и что любой объект, который вы хотите передать в буфер обмена, должен быть сериализуемым, иначе он не может быть передан другим процессам.
IList
когда он должен был бытьList
.