Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   forum.boolean.name > Программирование игр для компьютеров > С#

С# Средство разработки на платформе .Net

Ответ
 
Опции темы
Старый 08.06.2010, 23:16   #1
Dream
быдло
 
Регистрация: 05.08.2007
Сообщений: 1,435
Написано 614 полезных сообщений
(для 1,489 пользователей)
Радость Полу урок: Сериализация.

По просьбе автора две части статьи были соединены в одну тему.
Все комментарии были перемещены в отдельную тему. Просьба комментарии теперь писать только туда, чтобы не засорять этот топик!
- АВТОМАТ


Сериализация обьектов
.Вступление
Думаю много кто из вас делал загрузку/сохранение пареметров программы/игры, и часто сталкивался с разными проблемами связаными с этим делом.
Хотелось поделится опытом, услышать от вас идеи по улучшению.
1. Ввод в сериализацию
Как гласит вика
"Сериализация (в программировании) — процесс перевода какой-либо структуры данных в последовательность битов. Обратной к операции сериализации является операция десериализации — восстановление начального состояния структуры данных из битовой последовательности."
То есть это сохранения наших классов, с их, состоянием в файл. C# даёт удобную(но далеко не идеальную) возможность для работы с сериализцией System.Xml.Serialization. Он записывает данные в файл в виде Xml структуры, что удобно, если нужно будет править файл вручную, и в общем-то читабельней.
Минусом использования этого класса является то, что на сериализацию больших классов многократно (дупустим некое подобие базы данных) будет тратится довольно таки ощутимое время, что не совсем хорошо.
Давайте попробуем обойти это
2.
Один из способов избежать повторной сериализации структуры - сохранять шаблон, и при следующем вызове сериализации использовать его.
Сейчас напишем базовый класс для нашого сериализатора.
public class XmlHelper
    
{
        
#region members
        #endregion

        #region Static
        
public static XmlSerializer GetSerializer(Type type)
        {
           return 
null;
        }

        public static 
void WriteEntity(object objstring fileFullPath)
        {
        }

        public static 
T GetEntity<T>(string fileFullPath)
        {
            return 
null;
            
        }
        
#endregion
    

Примечание: как видите в коде используется #region советую и вам его использовать, это облегчает навигацию по коду, а также даёт возможность свернуть группы( например методы, поля, свойства и т.д.) чтобы нельзя было спутать их с другими участками кода
Примечание 2:для сериализатора нужно будет использовать следующие библиотеки
#region using
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml.Serialization;
#endregion 
Все методы объявлены как статик, потому что пока что нам не нужно создавать несколько экземпляров помощника, и можно будет обращаться из любого участка кода для сериализации нужного нам объекта.
Итак, давайте разберём по методом, что у нас есть. А есть у нас всего три метода, которые, пока что, как заглушки:
GetSerializer(Type type) - метод который будет возвращать сериализатор для указанного типа - "Type type"
WriteEntity(object obj, string fileFullPath) - метод который будет записывать в файл полученный объект (object obj) любого типа в файл (string fileFullPath). Путь к файлу желательно писать полный, во избежания недоразумений.
T GetEntity<T>(string fileFullPath) - метод который будет производить десериализацию указанного файла (string fileFullPath) в тип T, и возвратит нам экземпляр этого класса(T).
Давайте наполнять наш класс.
Во первых, создадим хранилище для сериализаторов, в таком деле я предпочитаю использовать коллекцию типа Hashtable (хотя тут дело каждого можно использовать и обычный IDictionary<string,XmlSerializer>)

private static readonly Hashtable hash = new Hashtable(); 
сделаем её приватной чтобы не было доступа не из нашего класса сериализатора (безопасный код, это важная вещь) и не было соблазна что-то засунуть туда.
Так как переменная у нас static, то можно сразу же её объявить, чтобы потом не переживать (хотя я рекомендую всё-таки делать конструкторы даже для статик классов).
Идем дальше. Заходим в метод GetSerializer
Обьявляем переменную для хранения возвращаемого сериализатора
XmlSerializer res
далее, так как приложение может быть многопоточное, нужно обезопасить себя, чтобы одновременно несколько обьектов не попытались получить сериализатор из нашей коллекции, так как это вызовет Ошибку.
и так лочим нашу коллекцию
lock (hash)
{


команда lock пытается получить к объекту (hash) монопольный доступ, и не начнет выполнение последующих за ней операторов, пока не получит этот самый доступ.
Внутри попытаемся получить сериализатор из нашей коллекции, в которой сохранены имена типов, который уже были сериализованы, и собственно сам сериализатор.
res hash[type.FullName] as XmlSerializer
так как в коллекции хранятся объекты в виде object, пытаемся привести его к XmlSerializer. если в колеции не будет этого типа, то переменная res будет равна null. идём дальше, проверим не равняется ли res null, и если равняется, прийдётся нам всётаки получить у системы сериализатор даного нудного класса.
if (res == null)
                {
                    
res = new XmlSerializer(type);
                    
hash[type.FullName] = res;
                } 
после получения сериализатора записываем его в коллекцию сериализаторов с ключём type.FullName - который соответствует полному имени класса, для которго мы создали сериализатор.
Вот собственно как должен после всего этого выглядеть метод

public static XmlSerializer GetSerializer(Type type)
        {
            
XmlSerializer res;
            
lock (hash)
            {
                
                
res hash[type.FullName] as XmlSerializer;
                if (
res == null)
                {
                    
res = new XmlSerializer(type);
                    
hash[type.FullName] = res;
                }
            }
            return 
res;
        } 
Теперь давайте заполним метод WriteEntity, который записывает класс в файл.
Для начала создаём сериализатор, с использованием только что написанного нами метода.
XmlSerializer serializer GetSerializer(obj.GetType()); 
Далее создадим StringBuilder, который помогает работать со строками и кодировками.
StringBuilder stringBuilder = new StringBuilder(); 
Также нужно создать класс-поток который производить работу со строками и передадим ему наш билдер строк.
StringWriter stringWriter = new StringWriter(stringBuilder CultureInfo.InvariantCulture); 
Начинаем сериализацию обьекта obj в поток:
serializer.Serialize(stringWriter obj); 
Закрываем поток:
stringWriter .Close(); 
Всё информация в виде строк сохранилась в наш билдер строк -stringBuilder, давайте получим всё в одну строку.
string xml stringBuilder .ToString(); 
Создадим экземпляр класса, который производить работу с записью информации в файл. Передадим в конструктор имя нужного нам файла который получили в параметрах метода:
StreamWriter sw = new StreamWriter(fileFullPath); 
Записываем:
sw.Write(xml); 
И не забываем закрыть поток.
sw.Close(); 
Результат в методе -

public static void WriteEntity(object objstring fileFullPath)
        {
            
XmlSerializer sr GetSerializer(obj.GetType());
            
StringBuilder sb = new StringBuilder();
            
StringWriter w = new StringWriter(sbCultureInfo.InvariantCulture);
            
sr.Serialize(wobj);
            
w.Close();
            
string xml sb.ToString();
            
StreamWriter sw = new StreamWriter(fileFullPath);
            
sw.Write(xml);
            
sw.Close();
        } 
Вот собственно и всё, мы сделали сериализацию объекта в файл.

Работать с этим классом так
XmlHelper.WriteEntity(MyClass,"С:\pron\list.extention"); 
Хочу заметить, что сериализуються ТОЛЬКО публичные свойства и поля класса(public) и называются они в файле также как вы назовёте их в коде.
Пока что всё.
Завтра напишу Про то как производить десериализацию из файла( а лучше не ждите и попробуйте сами сделать). а также про то, как назначить имена при сериализации и прочие нюансы. Удачи!
З.Ы. Спасибо ffinder за корректуру.

Последний раз редактировалось Dream, 11.06.2010 в 01:51.
(Offline)
 
Ответить с цитированием
Эти 14 пользователя(ей) сказали Спасибо Dream за это полезное сообщение:
ABTOMAT (08.06.2010), den (05.08.2010), Erkon (13.03.2013), Fatalix3d (08.06.2010), ffinder (09.06.2010), h1dd3n (09.06.2010), Harter (12.06.2010), IGR (08.06.2010), Lestar (18.06.2011), Nex (09.06.2010), pax (09.06.2010), Radnk (25.08.2012), Randomize (09.06.2010), SBJoker (08.06.2010)
Старый 10.06.2010, 03:07   #2
Dream
быдло
 
Регистрация: 05.08.2007
Сообщений: 1,435
Написано 614 полезных сообщений
(для 1,489 пользователей)
Радость Полу урок. Сериализация. Часть 2. Десериализация и параметры.

В предыдущей статье мы получили такой код :
public class XmlHelper
    
{
        
#region members
        
private static readonly Hashtable hash = new Hashtable(); 
        
#endregion

        #region Static
        
public static XmlSerializer GetSerializer(Type type)
        {
            
XmlSerializer res;
            
lock (hash)
            {

                
res hash[type.FullName] as XmlSerializer;
                if (
res == null)
                {
                    
res = new XmlSerializer(type);
                    
hash[type.FullName] = res;
                }
            }
            return 
res;
        }

        public static 
void WriteEntity(object objstring fileFullPath)
        {
            
XmlSerializer serializer GetSerializer(obj.GetType());
            
StringBuilder stringBuilder = new StringBuilder();
            
StringWriter w = new StringWriter(stringBuilderCultureInfo.InvariantCulture);
            
serializer.Serialize(wobj);
            
w.Close();
            
string xml stringBuilder.ToString();
            
StreamWriter sw = new StreamWriter(fileFullPath);
            
sw.Write(xml);
            
sw.Close();
        }
       
      
        
#endregion
    

Сегодня давайте приступим к десериализации, то есть в восстановлению класса из xml структуры, записанной ранее нами.
Это мы будем делать с помощью метода
T GetEntity<T>(string fileFullPath
, где Т - типа возвращаемого объекта, а string fileFullPath - путь к файлу из которого требуется извлечь структуру.
Выглядеть метод будет так
using (StreamReader reader = new StreamReader(fileFullPath))
            {
                
XmlSerializer dsr GetSerializer(typeof(T));
                return (
T)deSerializer.Deserialize(reader);
            } 
using (StreamReader reader = new StreamReader(fileFullPath))
            { 
мы создаём Потоковый ридер из файла, который мы получили в параметрах.
XmlSerializer deSerializerGetSerializer(typeof(T)); 
Так же как и в предыдущем методе, мы получаем сериализатор для даного типа.
в следующей строке, мы производим десериализацию из потока reader, с помощью полученного нами сериализатора deSerializer, и приводим его у требовавшемуся типу - Т который был указан при вызове метода:
return (T)deSerializer.Deserialize(reader); 
Вот собственно и всё! теперь можно записывать и получать экземпляры классов с помощью нашего помощника.

Вот пример кода:
Объявляем класс TempClass:
public class TempClass
    
{
        
#region _fields

        
private string _name;
        public 
int Id;
        
#endregion

        #region statics
        
public static int Count;
        public static 
int GetNextCount
        
{
            
get
            
{
                return ++
Count;
            }
        }
        
#endregion

        #region C'tos
        
public TempClass()
        {
            
Id GetNextCount;
        }
        
#endregion

        #region Propereties

        
public string Name
        
{
            
get
            
{
                return 
_name;
            }
            
set
            
{
                
_name value;
            }
        }

        
#endregion

    

Здесь я ввёл глобальные статические поля, что показать как работает сериализатор. при создании экземпляра класса TempClass, количество экземпляров увеличивается, что даёт нам возможность узнать какой по счёту этот экземпляр.
Далее:
class Program
    
{
       
        static 
void Main(string[] args)
        {
            
TempClass myClass=new TempClass();
            
myClass.Name "Xml test class";
            
XmlHelper.WriteEntity(myClass,@"C:\classes.xml");
            
myClass = new TempClass();
            
myClass.Name "Xml test class 2";
            
XmlHelper.WriteEntity(myClass, @"C:\classes1.xml");
         
TempClass deserializeClass XmlHelper.GetEntity<TempClass>(@"C:\classes.xml");
            
Console.Write(deserializeClass.Id+": name - "+deserializeClass.Name);
      }
    } 
Примечание: пример был создан на основе шаблона - Console application.

TempClass myClass=new TempClass();
            
myClass.Name "Xml test class"
Создаём экземпляр класса TempClass, и назначаем ему имя - "Xml test class"

Далее вызываем наш метотод для сериализации в файл @"C:\classes.xml":
XmlHelper.WriteEntity(myClass,@"C:\classes.xml"); 
Также повторяем для ещё одного экземпляра, для чистоты эксперимента:
myClass = new TempClass();
myClass.Name "Xml test class 2";
XmlHelper.WriteEntity(myClass, @"C:\classes1.xml"); 
Теперь, если посмотреть на диске C: вы увидите два Xml файла со структурой

<TempClass >
  <
Id>1</Id>
  <
Name>Xml test class</Name>
</
TempClass
Как в видите статические поля не сериализуюся.
Также поля, помеченные как приватные (а также как protected), тоже не сериализуются.

Остальные поля сериализовались с именем прописанном в коде.
В первом файле, поле Id будет равно 1, а во втором - 2, то есть можно быть уверенным что сериализовалось два разных экземпляра.

Идём дальше по коду.
TempClass deserializeClass XmlHelper.GetEntity<TempClass>(@"C:\classes.xml"); 
Здесь мы вызываем метод десериализации написанный нами в начале этой статьи. Пытаемся десериализировать файл "classes.xml".
Примечание: при десериализцаии вызывается конструктор по умолчанию (new()) который обязательно должен присутствовать в сериализуемом классе, также класс, который вы ходите сериализовать/десериализовать должен быть объявлен с модификатором видимости public.

и свойства полученного нами экземпляра в консоль, чтобы наглядно увидеть.
Console.Write(deserializeClass.Id+": name - "+deserializeClass.Name); 
в строке вы увидите что мы десериализовали из файла класс, который был объявлен и записан первым в файл classes.xml .

3.
А сейчас давайте поговорим о нюансах и некоторых возможностях серилизации/десериализации.

и так:
1)
Возможность исключения из сериализации/десериализации не нужных полей:
[XmlIgnore]
ставится перед полем/свойством, которое мы не хотим чтобы сериализировалось в файл.
Это может понадобится если ваш класс выполняет какие действия в свойствах, например, модифицируем на класс TempClass в класс MathClass и добавим ему несколько полей.
public class MathClass
    
{
        
#region _fields

        
private string _name;
        public 
int Id;
        private 
int _firstDigit;
        private 
int _secondDigit;

        
#endregion

        #region statics
        
public static int Count;
        
        public static 
int GetNextCount
        
{
            
get
            
{
                
Count++;
                return 
Count;
            }
        }
        
#endregion

        #region C'tos
        
public MathClass()
        {
            
Id GetNextCount;
        }
        
#endregion

        #region Propereties

        
public string Name
        
{
            
get
            
{
                return 
_name;
            }
            
set
            
{
                
_name value;
            }
        }

        public 
int SecondDigit
        
{
            
get { return _secondDigit; }
            
set _secondDigit value; }
        }

        public 
int FirstDigit
        
{
            
get { return _firstDigit; }
            
set _firstDigit value; }
        }
          [
XmlIgnore]

        public 
int Result
        
{
            
get
            
{
                return 
FirstDigit SecondDigit;
            }
            
        }
        
#endregion

    

Этот класс, при вызове получении свойства Result возвращает сумму двух полей - FirstDigit и
SecondDigit. но так как результат у нас обновляется автоматически нам нет надобности записывать его в файл, и мы ставим перед ним [XmlIgnore]. остальные же поля будут сериализованы в файл.
2)
В xml 3 типа структур:
- ROOT - коренная структура, в которую входят все под структуры. В этой роли выступает класс, который был передан на сериализацию. в нашем примере это класс MathClass. Посмотрите в xml, и вы увидите что основная структура тоже называется MathClass, это корень.
-Attribute - поля, которые будут записываться перед ">" начала текущей структуры.
- Element - под структуры в текущей структуре - по умолчанию, для всех свойств/полей класса при сериализации. В общем то, представляет собой сериализацию того класса, который содержится в этом самом поле/свойстве
Пример:
<MathClass Id="2" Name="Xml test class"> <!--Id и Name атрибуиты структуры-->
  <
SecondDigit>0</SecondDigit><!--Эллементы-->
  <
FirstDigit>0</FirstDigit><!--Эллементы-->
</
MathClass
Давайте попробуем изменить наш класс MathClass, чтобы получить такую структуру, как в примере.
Поставим перед полем Id модификатор
[XmlAttribute]
public 
int Id
, чтобы сделать его атрибутом класса. Также поступим и со свойством Name
[XmlAttribute]
        public 
string Name
        
{
            
get
            
{
                return 
_name;
            }
            
set
            
{
                
_name value;
            }
        } 
.
Теперь установим свойства SecondDigit и FirstDigit элементами нашего класса


[XmlElement]
        public 
int SecondDigit
        
{
            
get { return _secondDigit; }
            
set _secondDigit value; }
        }

        [
XmlElement]
        public 
int FirstDigit
        
{
            
get { return _firstDigit; }
            
set _firstDigit value; }
        } 
Вот и всё, теперь мы получим точна такую же структуру как в примере.
На сегодня всё, мы разобрались как считать структуру из файла, смогли установить какие поля нам не нужны при сохранении, а также, как делать нужные нам свойства полями.
В следующий раз я разберу как назначать мена сериализируемым объектам и ещё несколько нюансов, которые возникают при этом. До скорых!
(Offline)
 
Ответить с цитированием
Эти 10 пользователя(ей) сказали Спасибо Dream за это полезное сообщение:
ABTOMAT (10.06.2010), den (05.08.2010), h1dd3n (02.09.2010), Harter (12.06.2010), IGR (10.06.2010), Lestar (18.06.2011), Nex (10.06.2010), pax (10.06.2010), Radnk (25.08.2012), Randomize (10.06.2010)
Старый 11.06.2010, 02:04   #3
Dream
быдло
 
Регистрация: 05.08.2007
Сообщений: 1,435
Написано 614 полезных сообщений
(для 1,489 пользователей)
Радость Полу урок: Сериализация. Части 3. Параметры

Всем привет!
Сегодня мы продолжим разбирать параметры сериализации/десериализации.

У модификатор [XmlAttribute] есть конструктор
XmlAttribute(string AttributeName
Этим самым мы имеем возможность изменить имя атрибута, которое и будет записываться в наш файл. Это может пригодится, если вам потребуется в будущем работать в ручную с этим файлом ( например: вы делаете экспорт каких то данных из своей программы, а потом, вам может понадобится заглянуть в этот файл и что то проверить, или написать новый импортёр для этих данных, имя будет более информативным)
Такойже конструктор есть и у элементов:
XmlElemen(string elementName
Давайте модифицируем наш класс, который мы описывали в прошлой статье.
public class MathClass
    
{
        
#region _fields

        
private string _name;
        [
XmlAttribute("indexOfMathClass")]
        public 
int Id;
        private 
int _firstDigit;
        private 
int _secondDigit;
        
      
#endregion

        #region statics
        
public static int Count;
        
        public static 
int GetNextCount
        
{
            
get
            
{
                
Count++;
                return 
Count;
            }
        }
        
#endregion

        #region C'tos
        
public MathClass()
        {
            
Id GetNextCount;
        }
        
#endregion

        #region Propereties
        
[XmlAttribute("FirstName")]
        public 
string Name
        
{
            
get
            
{
                return 
_name;
            }
            
set
            
{
                
_name value;
            }
        }

        [
XmlElement("DataElementFirst")]
        public 
int SecondDigit
        
{
            
get { return _secondDigit; }
            
set _secondDigit value; }
        }

        [
XmlElement("DataElementSecond")]
        public 
int FirstDigit
        
{
            
get { return _firstDigit; }
            
set _firstDigit value; }
        }
        [
XmlIgnore]
        public 
int Result
        
{
            
get
            
{
                return 
FirstDigit SecondDigit;
            }
            
        }
      
        
#endregion

    

Давайте посмотрим как будет выглядеть после этого наша структура

<MathClass indexOfMathClass="1" FirstName="Xml test class">
  <
DataElementFirst>0</DataElementFirst>
  <
DataElementSecond>0</DataElementSecond>
</
MathClass
Вот то результат которого мы и добивались.

Хотел бы вернутся к первому пункту в списке структур - Root
Этому типу соответствует модификатор
[XmlRoot
Это позволяет нам сделать класс, который мы обьявляем с этой структурой, назначит главным в Xml, и он не сможет выступать в качестве элемента или атрибута, поэтому будьте осторожны.
У него также есть конструктор, который позволяет задавать имя структуры
[XmlRoot(string RootName)] 
Давайте посмотрим, поставим перед объявлением нашего класса модификатор Root
[XmlRoot("Root")]
public class 
MathClass 
Запустите, и посмотрите как изменилась структура в файле.

<Root indexOfMathClass="1" FirstName="Xml test class">
  <
DataElementFirst>0</DataElementFirst>
  <
DataElementSecond>0</DataElementSecond>
</
Root
.

Давайте ещё посмотрим пример, когда у класса есть поле другого класса, объявленного нами

public class ElementClass
    
{
        
#region _fields

        
private string _name;

        
#endregion

        #region C'tors

        
public ElementClass()
        {
            
        }

        
#endregion


        #region Propereties
        
[XmlAttribute("SubClassName")]
        public 
string Name
        
{
            
get { return _name; }
            
set _name value; }
        }

        
#endregion

    

добавим в класс MathClass поле и свойство, чтобы можно было рабоать с экземпляром этого класса.

private ElementClass _subClass;

 [
XmlElement]
        public 
ElementClass SubClass
        
{
            
get { return _subClass; }
            
set _subClass value; }
        } 

а также изменим немножко нашу основную функцию

static void Main(string[] args)
        {
            
MathClass myClass=new MathClass();
            
myClass.Name "Xml test class";
            
XmlHelper.WriteEntity(myClass,@"C:\classes.xml");

            
myClass = new MathClass();
            
myClass.Name "Xml test class";
            
myClass.SubClass=new ElementClass();
            
myClass.SubClass.Name "This is Sub Class!";
            
XmlHelper.WriteEntity(myClass, @"C:\classes1.xml");

            
MathClass deserializeClass XmlHelper.GetEntity<MathClass>(@"C:\classes.xml");
            
Console.Write(deserializeClass.Id+": name - "+deserializeClass.Name);
        } 
В этом коде мы присвоим свойству SubClass новый экземпляр этого класса.И присвоим ему имя.
После сериализации мы увидим что в файле classes1, появилось свойство SubClass.
Как видим поля, которые равны null, не сериализируется, если поле числового типа, то оно сериализируется в любом случае.

Теперь хочу кое что сказать по поводу свойств, о их преймуществах при сериализации по сравнению с полями и членами класса(field,members).
У свойств есть два поля -
get{} 
и 
set
{} 
при сериализации, для получения значения свойства вызывается поле get, при десериализации данные из файла передаются в поле set. В чём преимущество? Мы можем не сериализировать целый класс, и группу свойства, а запихнуть всё что нужно для восстановления состояния например в строку. Иногда на этом экономится довольно много места. а также улучшает читабельность структуры. Давайте немножко изменим предидущий пример.

Заменим модификатор свойства SubClass на
[XmlIgnore]
, чтобы оно не сериализировалось в файл.
Также добавим новое свойство - SubClassName:
[XmlAttribute("SubClassName")]
        public 
string SubClassName
        
{
            
//Вызывается при сериализации объкта
            
get
            
{
                
string retValue string.Empty;
                if (
_subClass != null)
                {
                    
retValue _subClass.Name;
                }
                return 
retValue;
            }
            
//Вызывается при десериализации объекта
            
set
            
{
                if (
_subClass == null)
                {
                    
_subClass = new ElementClass();
                }
                
_subClass.Name value;
            }


        } 
Теперь если вы посмотрите в xml структуру, то увидете что у структуры Root появился атрибут SubClassName, который содержит имя.

Далее...
Отступление.
Так как Си-шарп поддерживет ООП в полноймере, есть возможность зоздавать классы, наследуя их от других классов и интерфейсов. Часто бывает что нужно сериализовать множество разных классов, которые имеют общие поля. При использовании ООП, нет необходимости создвать несколько списков, для содержания разных типов обьектов. Тоесть движок игры, который обновляет состояния всех обьектов, а обьекты в свою очередь могут будь разных типов - 3д обьекты, 2д обькты, скрипты. Без ооп, нам бы пришлось держать 3 списка обьктов, чтобы обновлять их.

Так как следующий код, довольно обьёмный по сравнению с предидущими, я не буду коментировать каждую строку, я думаю вы и сами разберётесь.

public abstract class ObjectBase
    
{
        private 
string _name;

        [
XmlAttribute]
        public 
string Name
        
{

            
get
            
{
                return 
_name;
            }
            
set
            
{
                
_name value;
            }
        }
       public 
virtual void Update(int time)
        {

        }

    }

    public class 
Object3D:ObjectBase
    
{
        
#region _fields

        
private string _only3DParameter;
        
#endregion


        #region Propereties
       
public Object3D()
        {
            
Name "Object3D";
            
_only3DParameter "Parameters 3D";
        }
       

        public 
string Only3DParameter
        
{
            
get { return _only3DParameter; }
            
set _only3DParameter value; }
        }

        
#endregion

        #region Methods

        
public override void Update(int time)
        {
            
        }

        
#endregion

    
}

    public class 
Object2D ObjectBase
    
{
        
#region _fields

        
private string _only2DParameter;
        
#endregion

        #region C'tors
        
public Object2D()
        {
            
Name "Object2D";
            
_only2DParameter "Parameters 2D";
        }


        
#endregion

        #region Propereties

        

        
public string Only2DParameter
        
{
            
get { return _only2DParameter; }
            
set _only2DParameter value; }
        }

        
#endregion

        #region Methods

        
public override void Update(int time)
        {
            
        }

        
#endregion

    
}
    [
XmlRoot("SaveGame")]
    public class 
ForSerialize
    
{
        private List<
ObjectBase_listObject=new List<ObjectBase>();
        public 
ForSerialize()
        {
            
        }

        [
XmlElement("Object2D"typeof(Object2D))]
        [
XmlElement("Object3D"typeof(Object3D))]
        public List<
ObjectBaseListObject
        
{
            
get { return _listObject; }
            
set _listObject value; }
        }
        public 
void Update(int time)
        {
            
_listObject.ForEach(delegate(ObjectBase obj)
                                    {
                                        
obj.Update(time);
                                    }
                                    );
        }


    } 
Обьясню немного. ObjectBase - базовый класс для всех наших обьктов, как 2д так и 3д, содержит поля имя обьекта, и метод для обновления обьекта. Object2D и Object3D я создал просто для примера. ForSerialize - менеджер объектов, который будет обновлять их.

Ткпкрь посмотрите на параметры модификатора XmlElementв классе ForSerialize . как видите, мы обьявили два модификатора для одного свойства объекта. Конструктор его такой -
[XmlElement(string ElementNameType type)] 
Если при сериализации типа объекта будет равен type, то его имя при сериализации будет ElementName.
Это нужно для того, чтобы восстанавливать тип обьктов, от общего родителя как у нас. тоесть чтобы при сериализации Object3D десериализовался как Object3D а не просто ObjectBase.

Изменим основной метод нашей программы,
ForSerialize serialize=new ForSerialize();
            
Object3D object3D=new Object3D();
            
object3D.Name "NewObject3D - 1";
            
serialize.ListObject.Add(object3D);

            
Object2D object2D=new Object2D();
            
object2D.Name "NewObject 2D - 1";
            
serialize.ListObject.Add(object2D);

            
object3D = new Object3D();
            
object3D.Name "NewObject3D - 2";
            
serialize.ListObject.Add(object3D);
            
            
XmlHelper.WriteEntity(serialize,@"C:\Serialize.xml"); 
Здесь мы заполняем экземпляр класса ForSerialize 2D и 3D объектами, а потом сериализуем его в файл @"C:\Serialize.xml".
Структура этого файла будет выглядеть так -
<ForSerialize>
  <
Object3D Name="NewObject3D - 1">
    <
Only3DParameter>Parameters 3D</Only3DParameter>
  </
Object3D>
  <
Object2D Name="NewObject 2D - 1">
    <
Only2DParameter>Parameters 2D</Only2DParameter>
  </
Object2D>
  <
Object3D Name="NewObject3D - 2">
    <
Only3DParameter>Parameters 3D</Only3DParameter>
  </
Object3D>
</
ForSerialize
Вот вобщемто и всё, что я хотел рассказать про сериализации, ещё наврено много нюансов осталось не описаными, но лучше если вы сами их найдёте.
Со временем я возможно буду добавлять заметки в эту статью.
Я прикрепил к посту проект, который был использован в последнем примере.
В ближайшем будующем я возможно напишу статью по XNA. Удачи вам, и стремления к совершенству.
Вложения
Тип файла: rar SerializeTest.rar (3.3 Кб, 747 просмотров)
(Offline)
 
Ответить с цитированием
Эти 7 пользователя(ей) сказали Спасибо Dream за это полезное сообщение:
den (05.08.2010), h1dd3n (02.09.2010), Harter (12.06.2010), Lestar (18.06.2011), pax (11.06.2010), Radnk (25.08.2012), Randomize (26.05.2011)
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +4, время: 14:21.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com