Сериализация объектов в ручную – легко!

В любой книжке по шарпу рассказывают о том, что такое сериализация объектов. Напомню сериализация – это просто сохранение всех свойств объекта, например, на жесткий диск для последующей загрузки (десериализации) и использования в дальнейшем. Достаточно написать волшебное слово

перед описанием объекта, и его уже можно легко сохранить используя класс BinaryFormatter из System.Runtime.Serialization. Казалось бы все просто и чего еще можно хотеть… Рассмотрим ситуацию когда ваш объект изменяется в процессе написания новых версий программы. Вы добавите новое свойство и обнаружите, что чтение (десериализация) старых данных перестало работать, так как объект изменился. Можно управлять десериализацией вручную, однако это накладно.

Так вот, чтобы избавиться от этих проблем можно написать свой [де]сериализатор используя Reflection:

private static void WriteObject(object obj, StreamWriter writer)

{

Type t = obj.GetType();

PropertyInfo[] pi = t.GetProperties();

 

writer.WriteLine(Begin(t.Name));

//Store all props

foreach (PropertyInfo p in pi)

writer.WriteLine(FormXmlLine(p.Name, p.GetValue(obj, null).ToString()));

writer.WriteLine(End(t.Name));

}

private static string Begin(string name)

{

return “<“ + name + “>”;

}

 

private static string End(string name)

{

return “</” + name + “>”;

}

 

private static string FormXmlLine(string name, string value)

{

return ”  <“ + name + “>” + value + “</” + name + “>”;

}

 

Метод просто записывает значения всех свойств объекта в формате XML. Его можно легко расширить для сохранения вложенных объектов и коллекций, добавив проверку типа свойства и видоизменив к рекуррентному виду. Хотя это не всегда нужно.

Прочитать сохраненный объект можно так:

    //Lets read

    public static void ReadObject(string filename, object Obj)

    {

      Type ObjType = Obj.GetType();

 

      using (XmlReader reader = XmlReader.Create(filename))

      {        

        while (reader.Read())

        {

          if (reader.IsStartElement())

          {

 

            if (reader.Name == ObjType.Name)

            {

              //Do nothing!

            }

            else

            {

              PropertyInfo[] pi = ObjType.GetProperties();

              foreach (PropertyInfo p in pi)

                if (p.Name == reader.Name)

                {

                  reader.Read();

 

                  //Read the text content of the element.

                  if (p.PropertyType.Name == “String”)

                    p.SetValue(Obj, reader.ReadString(), null);

                  if (p.PropertyType.Name == “Int32″)

                    p.SetValue(Obj, reader.ReadContentAsInt(), null);

                  if (p.PropertyType.Name == “Int64″)

                    p.SetValue(Obj, reader.ReadContentAsInt(), null);                  

                  if (p.PropertyType.Name == “Long”)

                    p.SetValue(Obj, reader.ReadContentAsLong(), null);

                }

            }

 

          }

        }

      }

    }

 

Дополнив это дело нужными типами данных и проверкой ошибок, можно легко сохранять и читать объекты. Но, главное, теперь классы сохраняемых объектов можно видоизменять не заботясь о сериализации. Понятно, что формат XML можно заменить любым другим по вкусу и сохранять не на диск, а в базу данных.

  • SM

    А можно ничего не писать и использовать встроенный XmlSerializer.

  • Alexander

    К сведению
    Почему бы не воспользоваться DOM-ом при формировании тегов. и при проверке типов воспользоваться приемом типа typeof(Int32).Name?

  • Виталий Гмызин