2015-08-21 4 views
0

Я знаю, что это популярная тема, и я много исследовал, не найдя ответа на мою проблему.Xml десериализован в базовый класс вместо производных классов

У меня есть базовый класс IntroductionAction и 2 производных класса IntroductionActionComplex и IntroductionActionSimple. У меня есть список IntroductionAction объектов, к которым я добавил объекты обоих производных типов. Мои следующие классы:

[XmlInclude(typeof(IntroductionActionComplex))] 
[XmlInclude(typeof(IntroductionActionSimple))] 
public class IntroductionAction 
{ 
    public IntroductionAction() { } 
} 

public class IntroductionActionComplex : IntroductionAction 
{ 
    [XmlIgnore] 
    public string name { get; set; } 

    [XmlElement(ElementName = "QuestionString")] 
    public string question { get; set; } 

    [XmlElement(ElementName = "AnswerString")] 
    public List<string> answerStrings { get; set; } 

    public IntroductionActionComplex() 
    { 
     name = string.Empty; 
     question = null; 
     answerStrings = new List<string>(); 
    } 
} 

public class IntroductionActionSimple : IntroductionAction 
{ 
    [XmlIgnore] 
    public string name { get; set; } 

    [XmlText] 
    public string Value { get; set; } 

    public IntroductionActionSimple() 
    { 
     Value = string.Empty; 
    } 
} 

Я затем создать список следующим образом

[XmlElement("IntroductionAction")] 
public List<IntroductionAction> introductionActions { get; set; } 

Я использую XmlSerializer и все упорядочивает правильно. Это результирующий XML-список, содержащий один из каждого из производных классов, который является правильным.

<IntroductionAction> 
    <QuestionString> 
    test 
    </QuestionString> 
    <AnswerString> 
    test 
    </AnswerString> 
    <AnswerString> 
    test 
    </AnswerString> 
</IntroductionAction> 
<IntroductionAction> 
    test 
</IntroductionAction> 

Этот XML-файл будет на устройство, которое не читает его как XML, а просто ищет теги и делает любую работу, он должен делать и из-за того, что файл не может содержать каких-либо XSI или XSD-теги, отступы и т. Д., Которые обычно связаны с правильным XML.

Моей десериализация код прямо вперед:

public static T Deserialize_xml_Config<T>(string file1, T obj) 
{ 
    XmlSerializer deserializer = new XmlSerializer(obj.GetType()); 
    using (TextReader reader = new StreamReader(file1)) 
    { 
     return (T)deserializer.Deserialize(reader); 
    } 
} 

Наконец к моей проблеме. Когда я десериализую, он десериализуется в базовый класс IntroductionAction, а не в производные классы. Эти классы IntroductionAction являются частью гораздо более крупного объекта, который я сериализую/десериализую. Я попытался сделать базовый класс абстрактным, так как она не содержит функциональных возможностей, но я получаю сообщение об ошибке на десериализации говоря

Указанный тип аннотация: имя = «IntroductionAction»

Несмотря на мои XmlIncludes это, похоже, не найти производные классы.

Я попытался добавить типы в сериализатор, но это не сработало.

Любая помощь очень ценится.

Edit: Это то, что я имею в виду, добавив типы в сериализатором

XmlSerializer deserializer = new XmlSerializer(obj.GetType(), new Type [] { typeof(IntroductionActionComplex), typeof(IntroductionActionSimple) }); 
using (TextReader reader = new StreamReader(file1)) 
{ 
    return (T)deserializer.Deserialize(reader); 
} 

Кроме того, моя попытка при использовании XmlAttributeOverrides:

XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides(); 
var attrs = new XmlAttributes(); 
XmlElementAttribute attr = new XmlElementAttribute(); 
attr.ElementName = "IntroductionAction"; 
attr.Type = typeof(IntroductionActionComplex); 
attrs.XmlElements.Add(attr); 
attr.ElementName = "IntroductionAction"; 
attr.Type = typeof(IntroductionActionSimple); 
attrs.XmlElements.Add(attr); 
attrOverrides.Add(typeof(IntroductionAction), "IntroductionAction", attrs); 

XmlSerializer deserializer = new XmlSerializer(obj.GetType(), attrOverrides); 
using (TextReader reader = new StreamReader(file1)) 
{ 
    return (T)deserializer.Deserialize(reader); 
} 
+0

Добавить выше каждого класса в [XmlRoot (ElementName = "......")] с фактическим именем тега (это верхний/нижний регистр символов) чтобы указать, к какому классу вы хотите включить каждый тег. – jdweng

+0

Можете ли вы опубликовать то, что вы сделали для 'Я попытался добавить типы в сериализатор, но это не сработало'? Я считаю, что вам нужно переопределить атрибуты xml, но я хочу сначала посмотреть, что вы сделали. – SwDevMan81

+0

@jdweng довольно уверен, что это не сработает, потому что оба производных объекта должны быть под тем же именем тега i.e

ответ

0

Я думаю, что вы очень близки. Ниже приведен полный пример сохранения и загрузки XML-файла на основе типов производных классов. Это позволит сохранить узлы в качестве самого производного типа, поэтому загрузка обратно внутри будет сохранять желаемый тип, а не конвертировать обратно в базовый тип. Вам, вероятно, потребуется добавить обработку исключений, это было просто быстрое решение. Я не изменил вашу базу IntroductionAction или производные классы IntroductionActionComplex/IntroductionActionSimple.

public class RootNode 
{ 
    [XmlElement("IntroductionAction")] 
    public List<IntroductionAction> introductionActions { get; set; } 

    public RootNode() 
    { 
     introductionActions = new List<IntroductionAction>(); 
    } 

    private static XmlAttributeOverrides GetXmlAttributeOverrides() 
    { 
     XmlAttributeOverrides xml_attr_overrides = new XmlAttributeOverrides(); 
     XmlAttributes xml_attrs = new XmlAttributes(); 
     xml_attrs.XmlElements.Add(new XmlElementAttribute(typeof(IntroductionActionComplex))); 
     xml_attrs.XmlElements.Add(new XmlElementAttribute(typeof(IntroductionActionSimple))); 
     xml_attr_overrides.Add(typeof(RootNode), "introductionActions", xml_attrs); 
     return xml_attr_overrides; 
    } 

    // Add exception handling 
    public static void SaveToFile(RootNode rootNode, string fileName) 
    { 
     using (MemoryStream mem_stream = new MemoryStream()) 
     { 
     XmlSerializer serializer = new XmlSerializer(rootNode.GetType(), RootNode.GetXmlAttributeOverrides()); 
     serializer.Serialize(mem_stream, rootNode); 

     using (BinaryWriter output = new BinaryWriter(new FileStream(fileName, FileMode.Create))) 
     { 
      output.Write(mem_stream.ToArray()); 
     } 
     } 
    } 

    // Add exception handling 
    public static RootNode LoadFromFile(string fileName) 
    { 
     if (File.Exists(fileName)) 
     { 
     using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 
     { 
      using (TextReader reader = new StreamReader(file)) 
      { 
       XmlSerializer serializer = new XmlSerializer(typeof(RootNode), RootNode.GetXmlAttributeOverrides()); 
       return (RootNode)serializer.Deserialize(reader); 
      } 
     } 
     } 
     return null; 
    } 
} 

Программа испытаний:

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     RootNode obj = new RootNode(); 
     obj.introductionActions.Add(new IntroductionActionComplex() { question = "qTest", answerStrings = { "aTest1", "aTest2" }, name = "aName1" }); 
     obj.introductionActions.Add(new IntroductionActionSimple() { name = "aName2", Value = "aValue" }); 

     RootNode.SaveToFile(obj, "Test.xml"); 

     RootNode obj2 = RootNode.LoadFromFile("Test.xml"); 
    } 
} 
+0

В функции GetXmlAttributeOverrides() выше вы добавляете typeof (RootNode) при добавлении в xml_attr_overrides. Это относится к классу, в котором был создан и инициализирован список introductionActions? –

+0

@ M.Geaney - Да. Если вы хотите, чтобы узлы в XML были все «IntroductionAction» вместо имен производных классов, вы можете изменить его на «typeof (IntroductionAction)», и xml помечает каждый узел своим типом. По моему мнению, XML становится более подробным и немного менее ясным, но его другим вариантом. – SwDevMan81

+0

Я дал ему ход, но не повезло. Он по-прежнему десериализуется в 2 базовых класса объектов IntroductionAction вместо объектов IntroductionActionComplex и IntroductionActionSimple. –