序列化一个静态类?

如果我们序列化一个静态类会发生什么? 如果我们序列化,可以创build多个静态类的实例吗?

[Serializable] public static class MyClass { public static MyClass() { } public static bool IsTrue() { return true; } } 

假设我将XmlSerialize对象转换为XML文件,并在稍后将序列化为对象。 另一个副本存在于内存中(当somone第一次初始化静态时创build)。 请问,有两个副本的对象? 如果是,我们可以阻止? 它是否适用于任何遵循单例模式的类?

从来没有任何静态类的实例:它们都是抽象的,并在IL中密封,所以CLR将阻止任何正在创build的实例。 所以没有什么可以序列化的。 静态字段永远不会被序列化,这是静态类唯一的状态。

你关于XML序列化的问题是没有意义的,因为没有人可以创build静态类的实例来开始。

您不能使用内置的.NET序列化function序列化static类(或任何类)。 你只能序列化类的实例

您可以创build以下类:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.Serialization.Formatters.Soap; using System.Reflection; using System.IO; namespace SerializeStatic_NET { public class SerializeStatic { public static bool Save(Type static_class, string filename) { try { FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.Public); 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.Public); 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)) { field.SetValue(null, a[i,1]); } i++; }; return true; } catch { return false; } } } } 

您必须定义对System.Runtime.Serialization.Formatters.Soap的引用。

说,在你的程序中,你想保存下面的静态类:

 public static class A { public static string s; public static int i; public static double z; } 

您可以使用以下代码:

 bool ok = SerializeStatic.Save(typeof(A), "c:\\tests\\a.dat"); 

如果要加载保存的数据(在相同的程序或另一个程序中),请使用以下代码:

 bool ok2 = SerializeStatic.Load(typeof(A), "c:\\tests\\a.dat"); 

As,Ai,Az字段将获得新的加载值。

为什么不使用静态类的镜像的临时实例类呢?

 [XmlRoot] public class SerializeClass { public int Number { get; set; } } public static class SerializedClass { public static int Number { get; set; } public static void Serialize(Stream stream) { SerializeClass obj = new SerializeClass(); obj.Number = Number; XmlSerializer serializer = new XmlSerializer(typeof(SerializeClass)); serializer.Serialize(stream, obj); } public static void Deserialize(Stream stream) { XmlSerializer serializer = new XmlSerializer(typeof(SerializeClass)); SerializeClass obj = (SerializeClass)serializer.Deserialize(stream); Number = obj.Number; } } 

我知道这是一个黑客攻击,但它达到了同样的目的,同时仍允许在运行之前重构,并在运行时validation值。

我发现这个答案真的对我的设置类有用! 1000谢谢你!

但我不得不做一些改变,使其工作,由于不可序列化的对象,并由于servicepack兼容性更改为BinaryFormatter

 public class SerializeStatic { public static bool Save(Type static_class, string filename) { try { FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.Public); object[,] a = new object[fields.Length-1,2]; //one field can´t be serialized, so shouldn´t be counted int i = 0; foreach (FieldInfo field in fields) { if(field.Name == "db") continue; // db cant be serialized! so get away.. not very pretty but does its job :) a[i, 0] = field.Name; a[i, 1] = field.GetValue(null); i++; }; Stream f = File.Open(filename, FileMode.Create); BinaryFormatter formatter = new BinaryFormatter(); //Soapformatter -> .NET 4.5 -> doesn´t run under xp! // SoapFormatter formatter = new SoapFormatter(); formatter.Serialize(f, a); f.Close(); return true; } catch(Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); //Better error messages return false; } } public static bool Load(Type static_class, string filename) { try { FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.Public ); object[,] a; Stream f = File.Open(filename, FileMode.Open); BinaryFormatter formatter = new BinaryFormatter(); a = formatter.Deserialize(f) as object[,]; f.Close(); if (a.GetLength(0) != fields.Length-1) return false; foreach ( FieldInfo field in fields) for(int i=0;i< fields.Length-1;i++) //I ran into problems that some fields are dropped,now everyone is compared to everyone, problem fixed if (field.Name == (a[i, 0] as string)) field.SetValue(null, a[i,1]); return true; } catch(Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); return false; } } } 

另一个解决scheme,但读取和写入XML。 您也可以使用字段上方的[NonSerialized]属性来防止它被序列化。

 public static class SerializeStatic { public static bool Serialize(Type staticClass, string fileName) { XmlTextWriter xmlWriter = null; try { xmlWriter = new XmlTextWriter(fileName, null); xmlWriter.Formatting = Formatting.Indented; xmlWriter.WriteStartDocument(); Serialize(staticClass, xmlWriter); xmlWriter.WriteEndDocument(); return true; } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); return false; } finally { if (xmlWriter != null) { xmlWriter.Flush(); xmlWriter.Close(); } } } public static void Serialize(string name, object obj, XmlTextWriter xmlWriter) { Type type = obj.GetType(); XmlAttributeOverrides xmlAttributeOverrides = new XmlAttributeOverrides(); XmlAttributes xmlAttributes = new XmlAttributes(); xmlAttributes.XmlRoot = new XmlRootAttribute(name); xmlAttributeOverrides.Add(type, xmlAttributes); XmlSerializer xmlSerializer = new XmlSerializer(type, xmlAttributeOverrides); xmlSerializer.Serialize(xmlWriter, obj); } public static bool Serialize(Type staticClass, XmlTextWriter xmlWriter) { FieldInfo[] fieldArray = staticClass.GetFields(BindingFlags.Static | BindingFlags.Public); xmlWriter.WriteStartElement(staticClass.Name); foreach (FieldInfo fieldInfo in fieldArray) { if (fieldInfo.IsNotSerialized) continue; string fieldName = fieldInfo.Name; string fieldValue = null; Type fieldType = fieldInfo.FieldType; object fieldObject = fieldInfo.GetValue(fieldType); if (fieldObject != null) { if (fieldType.GetInterface("IDictionary") != null || fieldType.GetInterface("IList") != null) { Serialize(fieldName, fieldObject, xmlWriter); } else { TypeConverter typeConverter = TypeDescriptor.GetConverter(fieldInfo.FieldType); fieldValue = typeConverter.ConvertToString(fieldObject); xmlWriter.WriteStartElement(fieldName); xmlWriter.WriteString(fieldValue); xmlWriter.WriteEndElement(); } } } xmlWriter.WriteEndElement(); return true; } public static bool Deserialize(Type staticClass, string fileName) { XmlReader xmlReader = null; try { xmlReader = new XmlTextReader(fileName); Deserialize(staticClass, xmlReader); return true; } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); return false; } finally { if (xmlReader != null) { xmlReader.Close(); xmlReader = null; } } } public static object Deserialize(string name, Type type, XmlReader xmlReader) { XmlAttributeOverrides xmlAttributeOverrides = new XmlAttributeOverrides(); XmlAttributes xmlAttributes = new XmlAttributes(); xmlAttributes.XmlRoot = new XmlRootAttribute(name); xmlAttributeOverrides.Add(type, xmlAttributes); XmlSerializer xmlSerializer = new XmlSerializer(type, xmlAttributeOverrides); return xmlSerializer.Deserialize(xmlReader); } public static bool Deserialize(Type staticClass, XmlReader xmlReader) { FieldInfo[] fieldArray = staticClass.GetFields(BindingFlags.Static | BindingFlags.Public); string currentElement = null; while (xmlReader.Read()) { if (xmlReader.NodeType == XmlNodeType.EndElement) continue; if (xmlReader.NodeType == XmlNodeType.Element) { currentElement = xmlReader.Name; } foreach (FieldInfo fieldInfo in fieldArray) { string fieldName = fieldInfo.Name; Type fieldType = fieldInfo.FieldType; object fieldObject = fieldInfo.GetValue(fieldType); if (fieldInfo.IsNotSerialized) continue; if (fieldInfo.Name == currentElement) { if (typeof(IDictionary).IsAssignableFrom(fieldType) || typeof(IList).IsAssignableFrom(fieldType)) { fieldObject = Deserialize(fieldName, fieldType, xmlReader); fieldInfo.SetValueDirect(__makeref(fieldObject), fieldObject); } else if (xmlReader.NodeType == XmlNodeType.Text) { TypeConverter typeConverter = TypeDescriptor.GetConverter(fieldType); object value = typeConverter.ConvertFromString(xmlReader.Value); fieldInfo.SetValue(fieldObject, value); } } } } return true; } }