C#: сохраняем описание объектов в XML

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

/// <summary>
/// Экспортируем объект в XML
/// </summary>
/// <param name="parentXML">xml в который прописываем данные</param>
/// <returns></returns>
public virtual XmlElement AsXML(XmlDocument parentXML)
{

    XmlElement RootElemtnt = parentXML.CreateElement("Task");
    RootElemtnt.SetAttribute("Type", this.GetType().FullName);

    // Список свойсвт которые экспортируем
    string[] SaveProperty = new string[] { "Caption", "Num", "Active", "Type", "Command"};
    foreach (string NameProperty in SaveProperty)
    {
        SetXMLPropery(RootElemtnt, NameProperty);
    }

    return RootElemtnt;       
}

Основную работу по сохранению в XML, выполняет функция SetXMLPropery.

/// <summary>
/// Преобразуем значение данного объекта в XML
/// </summary>
/// <param name="xml_element">xml элемент в которой прописываем данные</param>
/// <param name="NameProperty">имя свойсва</param>
protected void SetXMLPropery(XmlElement xml_element, string NameProperty)
{
    var Property = this.GetType().GetProperty(NameProperty);
    string val = Property.GetValue(this, null).ToString();

    xml_element.InnerXml = xml_element.InnerXml + string.Format("<{0}></{0}>", NameProperty);
    xml_element[NameProperty].InnerText = val;
    xml_element[NameProperty].SetAttribute("Type", Property.PropertyType.FullName);
}

Если создадим новый класс (выполняющий функции элемента списка), то можно легко перегрузить метод. Например так:

public override XmlElement AsXML(XmlDocument parentXML)
{
    XmlElement root = base.AsXML(parentXML);
    SetXMLPropery(root, "newProperty"); // новое свойство нового класса
    return root;
}

Теперь нам осталось в класс отвечающий за список добавить функцию записывающую элементы списка в один файл.
В ниже переведенном примере, «ParentTask» — это класс элемента списка.
Сам список у меня статический и носит имя ListTask

/// <summary>
/// Записать в XML-файл
/// </summary>
/// <param name="fileName">имя файла</param>
public static void SaveToFileXML(string fileName)
{
    XmlDocument doc = new XmlDocument();
    XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", null, null);
    doc.AppendChild(dec);
    XmlElement root = doc.CreateElement("Tasks");
    doc.AppendChild(root);

    foreach (ParentTask task in ListTask.Items)
    {
        XmlElement new_element = task.AsXML(doc);
        root.AppendChild(new_element);
    }
    doc.Save(fileName);          
}

Теперь собственно сама загрузка. Состоит из 2-х шагов:

  1. Загрузка непосредственно самого XML-файла. Затем выбираем все подходящие по имени ветки XML. Если атрибут «Type» у этой ветки соответствует нашему типу объекта-элемента списка, производим чтение.
  2. Разбор нужной ветки XML через метод FromXML()

Собственно первый шаг:

/// <summary>
/// Прочитать список в XML
/// </summary>
/// <param name="fileName"></param>
public static void LoadFromFileXML(string fileName)
{           
    XmlDocument doc = new XmlDocument();
    doc.Load(fileName);
    XmlNodeList nodeList = doc.SelectNodes("//Task");
    foreach (XmlNode nodeTask in nodeList)
    {
        string NameType = nodeTask.Attributes["Type"].Value;    // Тип 
        Type RooType = System.Type.GetType(NameType);

        if (RooType == typeof(ParentTask))
        {
            ParentTask itemTask = new ParentTask();
            itemTask.FromXM(nodeTask);
            Items.Add(itemTask);
        }
    }
}

2-й шаг. Разбор нужной ветки XML

/// <summary>
/// Читает из XML свойства объекта
/// </summary>
/// <param name="parentXML">xml для чтения</param>
public virtual void FromXM(XmlNode parentXML)
{
    foreach (XmlNode xml in parentXML.ChildNodes)
    {
        string NameProperty = xml.LocalName;
        if (NameProperty == "Type")
            continue;

        string value_str = xml.InnerText;
        System.Reflection.PropertyInfo Property = this.GetType().GetProperty(NameProperty);
        object value_obj = Convert.ChangeType(value_str, Property.PropertyType);
        Property.SetValue(this, value_obj, null);
    }
}

Разметаться такой метод не заменит сериализацию, но позволит сохранять простые свойства объекта.

Запись опубликована автором в рубрике C# с метками .

C#: сохраняем описание объектов в XML: 2 комментария

  1. borismor

    Я честно пытался) Но не вышло.
    Не помню причину, но по моему потому что сам список у меня static.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *