Почему это десериализованное вызывает меня исключение Stackru?
Когда я пытаюсь десериализовать мой FooContainer (List), я получаю сообщение об ошибке. Пожалуйста, просто посмотрите последнюю часть этого кода.
public interface IFoo
{
object Value { get; }
}
public abstract class Foo<T> : IFoo
{
[XmlElement("Value")]
public T Value { get; set; }
[XmlIgnore]
object IFoo.Value { get { return Value; } }
}
public class FooA : Foo<string> { }
public class FooB : Foo<int> { }
public class FooC : Foo<List<Double>> { }
[XmlRoot("Foos")]
public class FooContainer : List<IFoo>, IXmlSerializable
{
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
XmlSerializer serial = new XmlSerializer(typeof(FooContainer));
serial.Deserialize(reader);
}
public void WriteXml(XmlWriter writer)
{
ForEach(x =>
{
XmlSerializer serial = new XmlSerializer(x.GetType(),
new Type[] { typeof(FooA), typeof(FooB), typeof(FooC) });
serial.Serialize(writer, x);
});
}
}
class Program
{
static void Main(string[] args)
{
FooContainer fooList = new FooContainer()
{
new FooA() { Value = "String" },
new FooB() { Value = 2 },
new FooC() { Value = new List<double>() {2, 3.4 } }
};
XmlSerializer serializer = new XmlSerializer(fooList.GetType(),
new Type[] { typeof(FooA), typeof(FooB), typeof(FooC) });
System.IO.TextWriter textWriter = new System.IO.StreamWriter(@"C:\temp\movie.xml");
serializer.Serialize(textWriter, fooList);
textWriter.Close();
XmlReader reader = XmlReader.Create(@"C:\temp\movie.xml");
var a = serializer.Deserialize(reader);
}
}
Что я делаю неправильно?
3 ответа
Вы, кажется, не понимаете, что IXmlSerializable
для. Он предназначен для переопределения поведения по умолчанию XmlSerializer
, Если вы просто раскрутить другой XmlSerializer
на самом деле сериализовать / десериализовать в вашем WriteXml
/ReadXml
методы, то да, вы получите StackruException
потому что этот сериализатор будет вызывать точно так же, WriteXml
/ReadXml
/ Метод, с которого он пришел на точно такой же объект.
Просто избавься от этого IXmlSerializable
реализация, так как она на самом деле ничего не делает. Или прочитайте эту статью CP:
Как правильно реализовать IXmlSerializable
В основном, вы должны использовать стандарт Read*
а также Write*
методы на XmlReader
или же XmlWriter
читать или писать объект.
Не обязательно всегда неправильно использовать XmlSerializer
внутри ReadXml
или же WriteXml
метод - если вы используете его для сериализации / десериализации другого объекта, который не равен ни одному из объявленных типов в графе объектов или не содержит его.
У меня была точно такая же проблема:
Мне кажется, что ты скучаешь set
в вашем интерфейсе IFoo
или класс Foo
, Без set
объект становится доступным только для чтения, и вы получите StackruException
при попытке десериализации XML в объект.
Я просто добавил set
на мои атрибуты, и вещь решила сама.
Я бы отладил это, чтобы убедиться, но я думаю, что ваша реализация ReadXml
является рекурсивным ReadXml
звонки Deserialize
, который вызывает ReadXml
, который вызывает Deserialize
, так далее.
ReadXml
следует прочитать xml, используя переданный ридер, и увлажнить объект (т.е. this
) на основе данных XML.
из MSDN
Метод ReadXml должен воссоздать ваш объект, используя информацию, записанную методом WriteXml.
Когда этот метод вызывается, читатель располагается в начале элемента, который оборачивает информацию для вашего типа. То есть непосредственно перед начальным тегом, который указывает начало сериализованного объекта. Когда этот метод возвращается, он должен прочитать весь элемент от начала до конца, включая все его содержимое. В отличие от метода WriteXml, платформа не обрабатывает элемент-оболочку автоматически. Ваша реализация должна сделать это. Несоблюдение этих правил позиционирования может привести к тому, что код будет генерировать непредвиденные исключения во время выполнения или повреждать данные.
При реализации этого метода вы должны учитывать возможность того, что злонамеренный пользователь может предоставить правильно сформированное, но недопустимое представление XML, чтобы отключить или иным образом изменить поведение вашего приложения.