Контекст
С данным вопросом встретился при работе над одним из проектов, в котором очень много настроек. В виду того что добавление новых настроек происходило по ходу разработки то выявилась необходимость сделать класс к которому можно обратится из любого модуля программы. Для этого конечно был использован статический класс, а назвали мы его AppSettings. Конечно можно было бы использовать Properties.Settings… Не буду вдаваться в детали, но этот вариант не подходил.
Суть проблемы
Из за того что класс является статическим обычная сериализация не работает. Давайте проверим. Допустим, у нас есть простой статический класс:
В общем если класс не был бы статическим, можно было бы использовать System.Xml.Serialization.XmlSerializer. Это не наш случай — класс у нас статический и в этом случае, по тому, что XmlSerializer.Serialize метод требует экземпляр класса, а не тип класса, то компилятор выдаст 'Test1.TestStatic' is a 'type' but is used like a 'variable'.
Решение
Погуглив немного, ничего внятного не нашёл. Единственное что я видел это как сеарилизировать класс у которого есть статические поля. В мозгах крутилась только Reflection. Ну чтож, после некоторых экспериментов сделал следующий класс:
Суть проста:
Загрузка из файла выполняется также. Единственное что по моему мнению стоит заметить: Если в нашем классе, в одном из полей будет другой класс, то в этом случае достаточно будет обозначить второй класс как [Serializable]. То есть если у нас есть такое объявление в TestStatiс:
Тогда класс BrowserSettings будет выглядеть примерно так:
Как использовать
Для сохранения используем:
Для загрузки:
С данным вопросом встретился при работе над одним из проектов, в котором очень много настроек. В виду того что добавление новых настроек происходило по ходу разработки то выявилась необходимость сделать класс к которому можно обратится из любого модуля программы. Для этого конечно был использован статический класс, а назвали мы его AppSettings. Конечно можно было бы использовать Properties.Settings… Не буду вдаваться в детали, но этот вариант не подходил.
Суть проблемы
Из за того что класс является статическим обычная сериализация не работает. Давайте проверим. Допустим, у нас есть простой статический класс:
public static class TestStatic
{
// Fields...
private static int _Counter;
public static int Counter
{
get { return _Counter; }
set
{
_Counter = value;
}
}
}
В общем если класс не был бы статическим, можно было бы использовать System.Xml.Serialization.XmlSerializer. Это не наш случай — класс у нас статический и в этом случае, по тому, что XmlSerializer.Serialize метод требует экземпляр класса, а не тип класса, то компилятор выдаст 'Test1.TestStatic' is a 'type' but is used like a 'variable'.
Решение
Погуглив немного, ничего внятного не нашёл. Единственное что я видел это как сеарилизировать класс у которого есть статические поля. В мозгах крутилась только Reflection. Ну чтож, после некоторых экспериментов сделал следующий класс:
public static class SerializeStatic
{
public static bool Save(Type static_class, string filename)
{
try
{
FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
object[,] a = new object[fields.Length, 2];
int i = 0;
foreach (FieldInfo field in fields)
{
a[i, 0] = field.Name;
a[i, 1] = field.GetValue(null);
i++;
};
Stream f = File.Open(filename, FileMode.Create);
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(f, a);
f.Close();
return true;
}
catch
{
return false;
}
}
public static bool Load(Type static_class, string filename)
{
try
{
FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
object[,] a;
Stream f = File.Open(filename, FileMode.Open);
SoapFormatter formatter = new SoapFormatter();
a = formatter.Deserialize(f) as object[,];
f.Close();
if (a.GetLength(0) != fields.Length) return false;
int i = 0;
foreach (FieldInfo field in fields)
{
if (field.Name == (a[i, 0] as string))
{
if (a[i, 1] != null)
field.SetValue(null, a[i, 1]);
}
i++;
};
return true;
}
catch
{
return false;
}
}
}
Суть проста:
- Получаем статические поля:
FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
- Создаём матрицу и вбиваем в неё название поля и значение
- Ну и потом через SoapFormater записываем в файл.
Загрузка из файла выполняется также. Единственное что по моему мнению стоит заметить: Если в нашем классе, в одном из полей будет другой класс, то в этом случае достаточно будет обозначить второй класс как [Serializable]. То есть если у нас есть такое объявление в TestStatiс:
public static BrowserSettings OperaSettings
{
get { return _OperaSettings; }
set
{
_OperaSettings = value;
}
}
Тогда класс BrowserSettings будет выглядеть примерно так:
[Serializable]
public class BrowserSettings
{
//...
}
Как использовать
Для сохранения используем:
SerializeStatic.Save(typeof(TestStatic), "file.xml");
Для загрузки:
if (!SerializeStatic.Load(typeof(AppSettings), "file.xml")) ;