MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Как можно сериализовать все переменные статического класса?"
Answer 862686
Буквально поставленная задача решается с помощью Reflection в сочетании с функциональностью сериализации коллекций в XML-тип
ArrayOfAnyType
. Как-то так:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.IO; using System.Xml; using System.Xml.Serialization; namespace WinformsTest { public static class WorkingClass { //несколько полей разных типов для примера... public static int a=0; public static string b = "Hello"; public static List<string> c = new List<string> { "Петр","Мария","Александр" }; //Сохраняет состояние всех статических полей текущего класса в XML-файл public static void Save(string file) { List<object> values = new List<object>(); List<Type> types = new List<Type>(); types.Add(typeof(string)); //найдем все статические поля FieldInfo[] vars = typeof(WorkingClass).GetFields( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ); //занесем все в коллекцию и найдем все возможные типы foreach (FieldInfo x in vars) { values.Add(x.Name); values.Add(x.GetValue(null)); if (!types.Contains(x.FieldType)) types.Add(x.FieldType); } //сериализуем коллекцию в файл XmlSerializer ser = new XmlSerializer(typeof(List<object>), types.ToArray()); Stream s = new FileStream(file, FileMode.Create); using (s) { ser.Serialize(s, values); } } //Считывает состояние всех статических полей текущего класса из XML-файла public static void Load(string file) { List<object> values; List<Type> types = new List<Type>(); types.Add(typeof(string)); //найдем все статические поля FieldInfo[] vars = typeof(WorkingClass).GetFields( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ); //найдем все возможные типы foreach (FieldInfo x in vars) { if(!types.Contains(x.FieldType)) types.Add(x.FieldType); } //загружаем коллекцию из файла XmlSerializer ser = new XmlSerializer(typeof(List<object>), types.ToArray()); Stream s = new FileStream(file, FileMode.Open); using (s) { values = (List<object>)ser.Deserialize(s); } for(int i =0 ; i<values.Count;i+=2) { var item = vars.Where(x => x.Name == (string)values[i]).First(); //найдем поле по имени if (item != null) { item.SetValue(null, values[i + 1]); //установим значение поля } } } } }
Получаемый XML выглядит так:
<?xml version="1.0"?> <ArrayOfAnyType xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <anyType xsi:type="xsd:string">a</anyType> <anyType xsi:type="xsd:int">0</anyType> <anyType xsi:type="xsd:string">b</anyType> <anyType xsi:type="xsd:string">Hello</anyType> <anyType xsi:type="xsd:string">c</anyType> <anyType xsi:type="ArrayOfString"> <string>Петр</string> <string>Мария</string> <string>Александр</string> </anyType> </ArrayOfAnyType>
Однако, на практике принято все делать немного по другому. Использование статических открытых переменных для хранения данных предметной области, помимо наличия обычных для "глобального состояния" проблем с масштабируемостью приложения, затрудняет синхронизацию доступа из разных потоков и разработку GUI. Вместо этого, лучше сделать нормальный класс и специальное статическое поле для "основного" экземпляра:
public class WorkingClass { public bool a {get;set;} public int b {get;set;} public Book c {get;set;} //.... static WorkingClass _Instance = new WorkingClass(); public static WorkingClass Instance { get { return _Instance; } } }
Тогда можно сериализовывать экземпляр _Instance штатными средствами. Обращаться к переменным из любого места программы можно через
WorkingClass.Instance.a
. Раз любой доступ к данным осуществляется через геттер одного свойства, при таком подходе легко обеспечить синхронизацию потоков и уведомление GUI об изменениях.
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.