Pull to refresh

Файл конфигурации, сохранение и загрузка

Файл конфигурации


При разработке приложения появляется необходимость сохранять и восстанавливать некоторые настройки приложения. Например, при работе с базами данных появляется желание не «зашивать» в код путь к базе данных, а хранить к каком-нибудь файле, чтобы его можно было изменить не пересобирая приложение, или сохранить имя пользователя, который входил в систему последний раз, чтобы потом его автоматически выбрать.

С одно стороны для этого можно используя сериализацию в XML. Но как показала практика, этот метод имеет некоторые недостатки. К одному из таких недостатков можно отнести невозможность сохранение private полей и свойств.

При увеличении размера файла конфигурации, появляется желание с группировать параметры по какому-то принципу и оставить комментарий, за что отвечает данный параметр. Таким образом получаем в итоге легко читаемый файл конфигурации, а при необходимости в него можно легко внести изменение.

Задачи для решения


Какие задачи необходимо решить для удобной работы с файлом конфигурации как программисту, так и пользователю:
  • должен позволять легко сохранять и восстанавливать настройки
  • должна быть возможность комментировать параметры
  • должна быть возможность группировать параметры
  • должен быть простой механизм для программирования


Решение поставленных задач


Файл конфигурации будет иметь следующий вид название параметра = значение. Если строка является комментарием, то в начале строки должен стоять символ решетка (#).

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

Для описания полей и свойств класса, которые подлежат сохранения реализован класс ConfigOptionAttribute, который является наследником от Attribute
/// /// Атрибут для автоматического сохрнения данных в файл конфигурации
/// Используется совмесно с потомками класса Colib.BaseConfig
///
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class ConfigOptionAttribute : Attribute
{
/// /// Название опции
///
public string Name { get; set; }

/// /// Коментарий
///
public string Comment { get; set; }

/// /// Шифровать при записи
///
public bool Security { get; set; }

/// /// Группа параметров
///
public string Group { get; set; }

/// /// Атрибут для автоматического сохрнения данных в файл конфигурации
///
/// Название опции
public ConfigOptionAttribute(string name)
{
Name = name;
Comment = "";
Security = false;
Group = " Global";
}

/// /// Преобразет строку в указаный тип. Если преобразование не поддерживается, то генерируется ошибка
///
/// строка значеия
/// в какой тип преобразовать
/// Объект типа type
internal static object ConvertTo(string value, Type type)
{
if (type == typeof (string))
{
return value;
}
if (type == typeof(int))
{
return int.Parse(value);
}
if (type == typeof(double))
{
return double .Parse(value);
}
if (type == typeof(bool))
{
return bool.Parse(value);
}
throw new Exception("Type to convert not supported");
}
}


Методы для работы с атрибутом определены в классе ConfigOptionAttribute (полный код).

Для сохранения настроек определен метод public void SaveToFile(Stream stream), который получает список всех полей и свойств класса, которые в описании имеют атрибут ConfigOptionAttribute, и сортирует их по группам:
List options = obj.GetType().GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(n => Attribute.IsDefined(n, typeof(ConfigOptionAttribute))).OrderBy(n => ((ConfigOptionAttribute)Attribute.GetCustomAttribute(n, typeof(ConfigOptionAttribute))).Group).ToList();

Далее для каждого элемента списка options в файл конфигурации записывается комментарий название группы, комментарий описание параметра и пара название параметра = значение:
string group = "";
foreach (MemberInfo info in options)
{
// получение атрибута метода
ConfigOptionAttribute attribute = (ConfigOptionAttribute)Attribute.GetCustomAttribute(info, typeof(ConfigOptionAttribute));
if (group != attribute.Group)
{
group = attribute.Group;
if (!string.IsNullOrEmpty(group))
{
sw.WriteLine("# " + group.Trim());
}
else
{
sw.WriteLine("##");
}
}
// запись коментария метода, если он есть
if (!string.IsNullOrEmpty(attribute.Comment))
{
sw.WriteLine(" # " + attribute.Comment);
}

// Запись значение поля или свойства
FieldInfo fieldInfo = info as FieldInfo;
if (fieldInfo != null)
{
sw.WriteLine(string.Format(" {0} = {1}", attribute.Name, fieldInfo.GetValue(obj)));
}
else
{
PropertyInfo propertyInfo = (PropertyInfo)info;
sw.WriteLine(string.Format(" {0} = {1}", attribute.Name, propertyInfo.GetValue(obj, null)));
}
}


Для загрузки параметров из файла конфигурации определен метод public void LoadFromFile(Stream stream), который считывает из файла конфигурации пару название параметра = значение, находит поле или свойство класса, у которому принадлежит атрибут с именем "название параметра" и присваивает ему "значение".

Для работы с файлом конфигурации необходимо сделать класс потомок от абстрактного класса BaseConfig:
class Config : BaseConfig
{
// Первый параметр всегда название параметра
[ConfigOption("Attribute 1", Group = "Группа 1")]
private string _attr1;

// будет добавлен в группу "Global"
[ConfigOption("Proprty 1", Comment = "Свойство 1")]
public string Attr1
{
get { return _attr1; }
set { _attr1 = value; }
}

// будет добавлен в группу "Global"
[ConfigOption("Attribute 2", Comment = "Тестовый атрибут")]
public string _attr2;
public string Attr2
{
get { return _attr2; }
set { _attr2 = value; }
}

[ConfigOption("BoolOption", Group = "Группа 2")]
public bool BoolOpt { get; set; }

[ConfigOption("IntOptions", Group = "Группа 2")]
public int IntOpt { get; set; }
}


Пример создания и сохранения файла конфигурации:
Config config = new Config() { Attr1 = "text attr 1", IntOpt = 345, BoolOpt = true };
var stream = new FileInfo("test2.conf").OpenWrite();
config.SaveToFile(stream);
stream.Close();
Close();


В результате будет создан файл test2.conf, который будет иметь следующий вид:
# Global
# Свойство 1
Proprty 1 = text attr 1
# Тестовый атрибут
Attribute 2 =
# Группа 1
Attribute 1 = text attr 1
# Группа 2
BoolOption = True
IntOptions = 345
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.