Используя C# .NET 2.0, у меня есть класс составных данных, в котором есть атрибут [Serializable]. Я создаю класс XMLSerializer и передаю его в конструктор:
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
Я получаю исключение:
There was an error reflecting type.
Внутри класса данных есть еще один составной объект. Должен ли он также иметь атрибут [Serializable], или, располагая его на верхнем объекте, он рекурсивно применяет его ко всем объектам внутри?





Посмотрите на внутреннее исключение, которое вы получаете. Он сообщит вам, в каком поле / свойстве возникают проблемы с сериализацией.
Вы можете исключить поля / свойства из XML-сериализации, украсив их атрибутом [XmlIgnore].
XmlSerializer не использует атрибут [Serializable], поэтому я сомневаюсь, что проблема в этом.
Обнаружил это при поиске в Google - моя конкретная проблема заключалась в том, что свойство в моем классе «быть сериализовано» как IList, когда ему нужно было быть List.
Как смотреть на «внутреннее исключение»?
@David: попробуйте {...} catch (Exception e) {Exception ie = e.InnerException}
или добавьте к часам '@exception'
Спасибо, этот ответ мне помог. Сначала я посмотрел на внутреннее исключение и просто увидел упоминание об основном классе. Но я понял, что могу углубиться в внутренние исключения из внутренних исключений, и, в конце концов, на 5 уровней ниже я нашел проблему. У меня были противоречивые занятия. Спасибо.
так же, как @LouisvanTonder, пришлось пройти несколько внутренних исключений, прежде чем я обнаружил, в каком классе отсутствует пустой конструктор. Спасибо!
Спасибо за подсказку @Roland! Я никогда не думал, что у вас есть доступ к этой информации. Очень полезный. Чтобы отладить свою проблему, я распечатал все внутренние исключения следующим образом: try {...} catch (Exception e) {/ * print e.Message * / for (Exception ie = e.InnerException; null! = Ie; ie; ie = ie.InnerException) {/ * распечатать ie.Message * /}}
@thehelix писать условия йоды не стоит.
@thehelix Я не знаю, буду ли я когда-нибудь использовать ваше выражение «йода», но мне нравится изучать еще один способ делать что-то, спасибо. Но действительно ли вы предлагаете принять InnerException из InnerException? Разве вы не имеете в виду: for(Exception TheExc = e; TheExc != null; TheExc = TheExc.InnerException){print TheExc.Message;} ??
@Roland, я обнаружил три внутренних исключения, детализировав и распечатав все вложенные InnerExceptions. Это выявило некоторую интересную информацию, которая в конечном итоге решила некоторые мои проблемы. Мне нравится выполнять отладку с подробным ведением журнала, поэтому меня это устраивает. :) Выражения Йоды - это у меня привычка, потому что за эти годы я достаточно раз обжигался ошибками присваивания, чтобы больше не тратить время на их отслеживание. Сейчас для меня это происходит автоматически, но я поддерживаю любое соглашение. :)
@Roland, большое спасибо за то, как проверить внутреннее исключение! У меня было аналогичное исключение, но оказалось, что это было просто потому, что другой мой класс был недоступен из-за его уровня защиты XD ... В общем, этот вопрос действительно помог мне, просто направив меня посмотреть его Внутреннее исключение. Оказывается, перед классом 9.9 просто не хватало «публики».
У меня было одно из моих свойств как IList, я изменил его на List и wallah!
для меня это было то, что у меня были [XmlArray] и [XmlArrayItem(typeof(Column))] над свойством без списка
Также обратите внимание, что вы не можете сериализовать элементы управления пользовательского интерфейса и что любой объект, который вы хотите передать в буфер обмена, должен быть сериализуемым, иначе он не может быть передан другим процессам.
Все объекты в графе сериализации должны быть сериализуемыми.
Поскольку XMLSerializer является черным ящиком, проверьте эти ссылки, если вы хотите продолжить отладку в процессе сериализации.
Я тоже думал, что атрибут Serializable должен быть на объекте, но если я не являюсь полным нубом (я нахожусь в середине ночного сеанса кодирования), следующие работы из 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 использует отражение над общедоступными свойствами.
Помните, что сериализованные классы должны иметь конструкторы по умолчанию (т.е. без параметров). Если у вас вообще нет конструктора, ничего страшного; но если у вас есть конструктор с параметром, вам также нужно добавить конструктор по умолчанию.
Спасибо за напоминание! Ненавижу, что это ошибка времени выполнения без небольшого объяснения.
Я повторяю эту ошибку снова и снова. спасибо, что напомнили мне использовать конструктор без параметров ^^
Также имейте в виду, что XmlSerializer не может сериализовать абстрактные свойства .. См. Мой вопрос здесь (в который я добавил код решения) ..
Я использовал класс NetDataSerialiser для сериализации
мои доменные классы. Класс NetDataContractSerializer.
Классы домена разделяются между клиентом и сервером.
Я обнаружил, что класс Dictionary в .Net 2.0 не сериализуется с помощью XML, но хорошо сериализуется при использовании двоичной сериализации.
Я нашел работу вокруг здесь.
Если вам нужно обрабатывать определенные атрибуты (например, словарь или любой класс), вы можете реализовать интерфейс 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 is covered in the official documentation, but the documentation states it's not intended for public use and provides no information beyond that. This indicates that the development team wanted to reserve the right to modify, disable, or even completely remove this extensibility hook down the road. However, as long as you're willing to accept this uncertainty and deal with possible changes in the future, there's no reason whatsoever you can't take advantage of it.
Поэтому я предлагаю реализовать собственные классы IXmlSerializable, чтобы избежать слишком сложных реализаций.
... может быть просто реализовать наш собственный класс XmlSerializer с помощью отражения.
Я недавно получил это в частичном классе веб-ссылки при добавлении нового свойства. Автоматически созданный класс добавлял следующие атрибуты.
[System.Xml.Serialization.XmlElementAttribute(Order = XX)]
Мне нужно было добавить аналогичный атрибут с порядком выше последнего в автоматически сгенерированной последовательности, и это исправило его для меня.
У меня была аналогичная проблема, и оказалось, что сериализатор не мог различить 2 класса, которые у меня были с тем же именем (один был подклассом другого). Внутреннее исключение выглядело так:
Оба типа «BaseNamespace.Class1» и «BaseNamespace.SubNamespace.Class1» используют имя типа XML «Class1» из пространства имен «». Используйте атрибуты XML, чтобы указать уникальное имя XML и / или пространство имен для типа.
Где BaseNamespace.SubNamespace.Class1 является подклассом BaseNamespace.Class1.
Что мне нужно было сделать, так это добавить атрибут к одному из классов (я добавил к базовому классу):
[XmlType("BaseNamespace.Class1")]
Примечание. Если у вас есть несколько уровней классов, вам также необходимо добавить к ним атрибут.
Это решило проблему для меня, спасибо, +1; У меня была аналогичная настройка с несколькими объектами Processor *, каждый из которых имел внутренний класс Config. Среда выполнения не смогла различить SomeNS.Processor1.Config и SomeNS.Processor2.Config.
Я получил ту же ошибку и обнаружил, что проблема в свойстве типа IEnumerable<SomeClass>. Похоже, что IEnumerable нельзя сериализовать напрямую.
Вместо этого можно было использовать List<SomeClass>.
У меня была ситуация, когда порядок был одинаковым для двух элементов подряд
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]
.... какой-то код ...
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]
Когда я изменил код, чтобы увеличить порядок на единицу для каждого нового свойства в классе, ошибка исчезла.
Наиболее частые причины на мой взгляд:
- the object being serialized has no parameterless constructor
- the object contains Dictionary
- the object has some public Interface members
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
Или же
[XmlIgnore]
string [] strFielsName {get;set;}
У меня была такая же проблема, и в моем случае объект имел ReadOnlyCollection. Для сериализации коллекция должна реализовывать метод Add.
Это неправильный ответ на вопрос. На этот вопрос уже есть еще 15 ответов. Если вы считаете, что ваш ответ лучше других, вы должны предоставить о нем более подробную информацию. Предоставление кода и фрагментов вывода всегда помогает пользователям. Перед тем, как публиковать свои ответы, подумайте о прочтении -> stackoverflow.com/help/how-to-answer
У меня есть несколько иное решение, чем все описанное здесь, так что для любой будущей цивилизации вот мое!
Я объявил тип данных «время», поскольку исходным типом был TimeSpan, который впоследствии был изменен на String:
[System.Xml.Serialization.XmlElementAttribute(DataType = "time", Order=3)]
однако фактический тип был строкой
public string TimeProperty {
get {
return this.timePropertyField;
}
set {
this.timePropertyField = value;
this.RaisePropertyChanged("TimeProperty");
}
}
удалив свойство DateType, можно сериализовать Xml
[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string TimeProperty {
get {
return this.timePropertyField;
}
set {
this.timePropertyField = value;
this.RaisePropertyChanged("TimeProperty");
}
}
Я получал ту же ошибку, когда создавал свойство с типом данных - Type. По этому я получал ошибку - Произошла ошибка, отражающая тип. Я продолжал проверять «InnerException» каждого исключения из док-станции отладки и получил конкретное имя поля (которое было Type) в моем случае. Решение такое:
[XmlIgnore]
public Type Type { get; set; }
Иногда этот тип ошибки возникает из-за того, что у вас нет конструктора класса без аргумента.
У моего объекта было поле Uri, которое вызвало это исключение; класс Uri не имеет конструктора без параметров. Спасибо за чаевые.