Как нужно записывать в xml-файл объекты класса? Я сделал это так, но при добавлении листа (Leaf) появляется исключение:
InvalidOperationException: Тип TreeS.Leaf не ожидался. Используйте атрибут XmlInclude или SoapInclude для задания типов, которые не известны как статические.
Что нужно исправить?
using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace TreeS
{
public abstract class Question
{
[XmlElement("Question")]
public string name;
public Question()
{
}
public Question(string name)
{
this.name = name;
}
public abstract void Display();
public abstract void Add(Question c);
public abstract void Remove(Question c);
public virtual void Print()
{
Console.WriteLine(name);
}
}
public class Answer : Question
{
[XmlArray("Question1"), XmlArrayItem("Leaf")]
private List<Question> children = new List<Question>();
public List<Question> GetChildren { get => children; }
public Answer()
{
}
public Answer(string name)
: base(name)
{
}
public override void Add(Question component)
{
children.Add(component);
}
public override void Remove(Question component)
{
children.Remove(component);
}
public override void Display()
{
Console.WriteLine(name);
foreach (Question component in children)
{
component.Display();
}
}
public override void Print()
{
Console.WriteLine("Вопрос: " + name);
if (children.Count != 0)
{
Console.WriteLine("Ответы:");
for (int i = 0; i < children.Count; i++)
{
children[i].Print();
}
Console.WriteLine('\n');
}
}
}
public class Leaf : Question
{
public Leaf()
{
}
public Leaf(string name)
: base(name)
{
}
public override void Display()
{
Console.WriteLine(name);
}
public override void Add(Question component)
{
throw new NotImplementedException();
}
public override void Remove(Question component)
{
throw new NotImplementedException();
}
}
class Program
{
public static void Main()
{
Question question = new Answer("123");
Question question1 = new Answer("5");
Question answer = new Leaf("qwe");
Question answer1 = new Answer("asd");
question.Add(question1);
question.Add(answer);
question.Add(answer1);
question1.Add(answer);
question.Print();
CreateXML("tree.xml", question);
Answer question2 = GetXML("tree.xml");
Console.ReadKey();
}
private static void CreateXML(string filename, Question question)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Answer));
StringWriter stringWriter = new StringWriter();
TextWriter writer = new StreamWriter(filename);
xmlSerializer.Serialize(writer, question);
xmlSerializer.Serialize(stringWriter, question);
writer.Close();
}
private static Answer GetXML(string filename)
{
XmlSerializer serializer = new XmlSerializer(typeof(Answer));
FileStream fs = new FileStream(filename, FileMode.Open);
Answer collection;
collection = (Answer)serializer.Deserialize(fs);
return collection;
}
}
}
Делал по примеру Компоновщик
Чтобы (де)сериализация заработала, нужно сделать то, что сказано в описании ошибки. Добавляем атрибуты XmlInclude:
[XmlInclude(typeof(Answer))]
[XmlInclude(typeof(Leaf))]
public abstract class Question
Благодаря им сериализатор знает, какие классы-потомки могут оказаться вместо базового класса.
Оставим в стороне иерархию ваших классов (с какой стати ответ наследует от вопроса?), поговорим о коде сериализации.
В метод CreateXML передаётся тип Question, а сериализатор создаётся для типа Answer. Но ведь там может оказаться и Leaf.
Из метода GetXML возвращается тип Answer - это явно подогнано под тип сериализатора в предыдущем методе. Явные нарушения логики работы.
Не меняя логику ваших методов, просто перепишу их, чтобы сделать более устойчивыми к возможным исключениям.
private static void CreateXML(string filename, Question question)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Answer));
using (var writer = new StreamWriter(filename))
{
xmlSerializer.Serialize(writer, question);
}
}
private static Answer GetXML(string filename)
{
XmlSerializer serializer = new XmlSerializer(typeof(Answer));
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
Answer answer = (Answer)serializer.Deserialize(fs);
return answer;
}
}
У вас зачем-то делается сериализация в StringWriter.
И почему имя локальной переменной collection?
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости