none
Сериализация нескольких классов RRS feed

  • Вопрос

  • На данный момент пишу XmlParser для чтения и записи xml файлов и возник вопрос. У меня очень много наследуемых классов и возник такой вопрос что делать если мне нужно сериализовать несколько классов одновременно? Для записи у меня такой метод:

    public void Save<T>(T obj, string fileName)
        {
            XmlSerializer ser = new XmlSerializer(typeof(T));
            FileStream fs = new FileStream(fileName, FileMode.Create);
            ser.Serialize(fs, obj);
            fs.Flush();
            fs.Close();
        }
    Как видно из метода я могу сериализовать любой один класс, а что делать если допустим мне надо сериализовать вместе следующие классы: BentTube, Macro, Hole и ещё такие классы OvalTube, ConeIntersection, Slot. Заранее неизвестно какие классы должны быть сериализованы. Ведь вместе OvalTube мне допустим нужно будет сериализваоть и Hole, Slot. Подскажите пожалуйста, что можно сделать. Можно сделать и со списком но там нужно конкретно указывать какие классы необходимо сериализовать.
    4 октября 2012 г. 6:50

Ответы

  • Опять же не ясно, эта структура xml-файла задана жёстко извне техническим заданием, или лишь примерно должна быть такой?

    Я бы ввёл дополнительный класс (назвал его TubeCut), и сделал примерно так:

    using System;
    using System.Collections.Generic;
    using System.Xml;
    using System.Xml.Serialization;
    
    namespace ConApp_114
    {
        [XmlInclude(typeof(BentTube))]
        [XmlInclude(typeof(OvalTube))]
        public class Tube
        {
            public int WallThickness;
            public int Diameter;
        }
        public class BentTube : Tube { }
        public class OvalTube : Tube { }
    
        [XmlInclude(typeof(Slot))]
        [XmlInclude(typeof(Macro))]
        [XmlInclude(typeof(Hole))]
        public class Intersection
        {
            public int Diameter;
            public int AxisVector;
            public int AxisPoint;
        }
        public class Slot : Intersection { }
        public class Macro : Intersection { }
        public class Hole : Intersection { }
    
        public class TubeCut
        {
            public Tube Part;
            public List<Intersection> Intersections = new List<Intersection>();
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    var bentTube = new BentTube();
                    var macro = new Macro();
                    var hole = new Hole();
    
                    var tubeCut = new TubeCut();
                    tubeCut.Part = bentTube;
                    tubeCut.Intersections.Add(macro);
                    tubeCut.Intersections.Add(hole);
    
                    var program = new Program();
                    program.Save(tubeCut, "test.txt");
    
                    var tubeCut2 = program.Load("test.txt");
    
                    Console.WriteLine(tubeCut2.Part.GetType());
                    Console.WriteLine(tubeCut2.Intersections.Count);
                    foreach (var item in tubeCut2.Intersections)
                        Console.WriteLine(item.GetType());
                }
                catch (Exception ex) { Console.WriteLine(ex.Message); }
            }
    
            public void Save(TubeCut tubeCut, string fileName)
            {
                var settings = new XmlWriterSettings { Indent = true };
                using (var writer = XmlWriter.Create(fileName, settings))
                {
                    var ser = new XmlSerializer(typeof(TubeCut));
                    ser.Serialize(writer, tubeCut);
                }
            }
    
            public TubeCut Load(string fileName)
            {
                TubeCut tubeCut;
                using (var reader = XmlReader.Create(fileName))
                {
                    var ser = new XmlSerializer(typeof(TubeCut));
                    tubeCut = (TubeCut)ser.Deserialize(reader);
                }
                return tubeCut;
            }
        }
    }

    Естественно, поля следует заменить на свойства.

    При этом выходной файл получается такого формата:

    <?xml version="1.0" encoding="utf-8"?>
    <TubeCut xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Part xsi:type="BentTube">
        <WallThickness>0</WallThickness>
        <Diameter>0</Diameter>
      </Part>
      <Intersections>
        <Intersection xsi:type="Macro">
          <Diameter>0</Diameter>
          <AxisVector>0</AxisVector>
          <AxisPoint>0</AxisPoint>
        </Intersection>
        <Intersection xsi:type="Hole">
          <Diameter>0</Diameter>
          <AxisVector>0</AxisVector>
          <AxisPoint>0</AxisPoint>
        </Intersection>
      </Intersections>
    </TubeCut>

    Годится?

    • Помечено в качестве ответа Abolmasov Dmitry 9 октября 2012 г. 7:08
    • Снята пометка об ответе Abolmasov Dmitry 9 октября 2012 г. 7:08
    • Помечено в качестве ответа nigina_1989 9 октября 2012 г. 13:30
    • Снята пометка об ответе nigina_1989 9 октября 2012 г. 13:31
    • Помечено в качестве ответа nigina_1989 9 октября 2012 г. 13:36
    • Снята пометка об ответе nigina_1989 9 октября 2012 г. 16:53
    • Помечено в качестве ответа nigina_1989 10 октября 2012 г. 9:59
    7 октября 2012 г. 14:50

Все ответы

  •             System.Type type = typeof(MyType1);
    
                var extraTypes = new Type[] 
                    { 
                        typeof(MyType2), 
                        typeof(MyType3),
    }; XmlSerializer formatter = new XmlSerializer(type, extraTypes); TextWriter str2 = new StreamWriter(filename, false, Encoding.UTF8); try { formatter.Serialize(str2, this.blablabla); } catch { } str2.Close(); formatter = null;

    Я делаю так с доп типами,
    правда всё равно в доп типах указывать приходится (переменная extraTypes),
    а то потом ругается.
    так что наверное у меня не лучше решение,
    подождём чего более знающие скажут.

    у меня типы 2 и 3 наследуются от 1,
    но и без того вроде можно

    • Изменено INFEL8 4 октября 2012 г. 7:32
    4 октября 2012 г. 7:26
  • nigina_1989

    Какова иерархия перечисленных классов? Имеют ли они общего наследника?

    Где хранятся сериализуемые классы? Ведь мало сохранить их, нужно потом прочитать обратно. Куда читать будем?

    Из приведённого кода неясно, как потом читать созданный таким образом файл. Как определить, что за объект туда сериализован?

    4 октября 2012 г. 15:07
  • Структура такова:

    public class Tube {}
    
    public class BentTube : Tube {}
    
    public class OvalTube : Tube {}
    
    public class Intersection {}
    
    public class Slot : Intersection {}
    
    public class Macro : Intersection {}
    
    public class Hole : Intersection {}

    И допустим мне нужно будет сериализовать OvalTube c Macro, Hole,  или даже BentTube c Slot,  или BentTube c Hole, Macro и Slot и тоже самое с OvalTube. Вот с чтением у меня тоже проблемка выходит. Посоветуйте пожалуйста какое нибудь решение, как можно обойти эту проблемку.


    • Изменено nigina_1989 4 октября 2012 г. 16:24
    4 октября 2012 г. 16:22
  • Хорошо, иерархия понятна.

    Однако, неясно, сколько создаётся экземпляров этих типов. Хранятся ли они в вашей программе в каких-то коллекциях (каких?), или это единичные экземпляры, являющиеся полями/свойствами основного класса?

    Имена файлов, куда сохраняются данные, известны изначально (никогда не меняются) или могут быть произвольными в ходе выполнения программы?

    В самом первом сообщении указано, что вы пишете xml парсер. Однако используете XmlSerializer. Так всё-таки нужен свой парсер (зачем?) или просто нужно максимально просто сохранять/читать произвольные данные?

    5 октября 2012 г. 14:26
  • Коллекции не использую, всё хранится в полях. Это всё единичные экземпляры. На счёт имени файлов, при сохранении можно задать имя или по имени класса, так как известно заранее что любым первым классом, который должен быть сериализован является только один наследник класса Tube, а вот классы наследники Intersection должны сохранятся после, но не известно заранее какой именно, известно только что их может быть несколько, от одного до двух, или трёх. Всё таки для создания и чтения Xml-файла будет использоваться XmlSerializer, так как XmlDocument, XmlWriter и XmlReader не подходят в моём случае. В любом случае структура Xml-файла должна быть такой: 

    <?xml version="1.0" encoding="utf-8" ?>
    <TubeCut xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Part>
        <Parameter>
          <Type>OvalTube</Type>
          <WallThickness>0</WallThickness>
          <Diameter>0</Diameter>
        </Parameter>
      </Part>
      <Intersection>
        <Type>TubeIntersection</Type>
        <Diameter>0</Diameter>
        <AxisVector>
          <X>0.000</X>
          <Y>0.000</Y>
          <Z>0.000</Z>
        </AxisVector>
        <AxisPoint>
          <X>0.000</X>
          <Y>0.000</Y>
          <Z>0.000</Z>
        </AxisPoint>
      </Intersection>
    </TubeCut>

    7 октября 2012 г. 8:26
  • Опять же не ясно, эта структура xml-файла задана жёстко извне техническим заданием, или лишь примерно должна быть такой?

    Я бы ввёл дополнительный класс (назвал его TubeCut), и сделал примерно так:

    using System;
    using System.Collections.Generic;
    using System.Xml;
    using System.Xml.Serialization;
    
    namespace ConApp_114
    {
        [XmlInclude(typeof(BentTube))]
        [XmlInclude(typeof(OvalTube))]
        public class Tube
        {
            public int WallThickness;
            public int Diameter;
        }
        public class BentTube : Tube { }
        public class OvalTube : Tube { }
    
        [XmlInclude(typeof(Slot))]
        [XmlInclude(typeof(Macro))]
        [XmlInclude(typeof(Hole))]
        public class Intersection
        {
            public int Diameter;
            public int AxisVector;
            public int AxisPoint;
        }
        public class Slot : Intersection { }
        public class Macro : Intersection { }
        public class Hole : Intersection { }
    
        public class TubeCut
        {
            public Tube Part;
            public List<Intersection> Intersections = new List<Intersection>();
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    var bentTube = new BentTube();
                    var macro = new Macro();
                    var hole = new Hole();
    
                    var tubeCut = new TubeCut();
                    tubeCut.Part = bentTube;
                    tubeCut.Intersections.Add(macro);
                    tubeCut.Intersections.Add(hole);
    
                    var program = new Program();
                    program.Save(tubeCut, "test.txt");
    
                    var tubeCut2 = program.Load("test.txt");
    
                    Console.WriteLine(tubeCut2.Part.GetType());
                    Console.WriteLine(tubeCut2.Intersections.Count);
                    foreach (var item in tubeCut2.Intersections)
                        Console.WriteLine(item.GetType());
                }
                catch (Exception ex) { Console.WriteLine(ex.Message); }
            }
    
            public void Save(TubeCut tubeCut, string fileName)
            {
                var settings = new XmlWriterSettings { Indent = true };
                using (var writer = XmlWriter.Create(fileName, settings))
                {
                    var ser = new XmlSerializer(typeof(TubeCut));
                    ser.Serialize(writer, tubeCut);
                }
            }
    
            public TubeCut Load(string fileName)
            {
                TubeCut tubeCut;
                using (var reader = XmlReader.Create(fileName))
                {
                    var ser = new XmlSerializer(typeof(TubeCut));
                    tubeCut = (TubeCut)ser.Deserialize(reader);
                }
                return tubeCut;
            }
        }
    }

    Естественно, поля следует заменить на свойства.

    При этом выходной файл получается такого формата:

    <?xml version="1.0" encoding="utf-8"?>
    <TubeCut xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Part xsi:type="BentTube">
        <WallThickness>0</WallThickness>
        <Diameter>0</Diameter>
      </Part>
      <Intersections>
        <Intersection xsi:type="Macro">
          <Diameter>0</Diameter>
          <AxisVector>0</AxisVector>
          <AxisPoint>0</AxisPoint>
        </Intersection>
        <Intersection xsi:type="Hole">
          <Diameter>0</Diameter>
          <AxisVector>0</AxisVector>
          <AxisPoint>0</AxisPoint>
        </Intersection>
      </Intersections>
    </TubeCut>

    Годится?

    • Помечено в качестве ответа Abolmasov Dmitry 9 октября 2012 г. 7:08
    • Снята пометка об ответе Abolmasov Dmitry 9 октября 2012 г. 7:08
    • Помечено в качестве ответа nigina_1989 9 октября 2012 г. 13:30
    • Снята пометка об ответе nigina_1989 9 октября 2012 г. 13:31
    • Помечено в качестве ответа nigina_1989 9 октября 2012 г. 13:36
    • Снята пометка об ответе nigina_1989 9 октября 2012 г. 16:53
    • Помечено в качестве ответа nigina_1989 10 октября 2012 г. 9:59
    7 октября 2012 г. 14:50