如果序列化静态类会发生什么?如果我们序列化它,可以创建多个静态类的实例吗?
[Serializable]
public static class MyClass
{
public static MyClass()
{
}
public static bool IsTrue()
{
return true;
}
}
假设我将对象XmlSerialize为XML文件,稍后我反序列化回一个对象。另一个副本存在于内存中(当somone第一次直观地表达静态calss时创建)。请问,有两个副本的对象?如果是的话,我们可以阻止吗?它是否适用于遵循单例模式的任何类?
答案 0 :(得分:55)
永远不会有静态类的任何实例:它们都是抽象的并且密封在IL中,因此CLR将阻止创建任何实例。因此没有什么可序列化的。静态字段永远不会被序列化,这是静态类可以拥有的唯一状态。
关于XML序列化的问题毫无意义,因为没有人能够创建静态类的实例。
答案 1 :(得分:17)
您无法使用内置的.NET序列化功能序列化static
类(或任何类)。您只能序列化实例类。
答案 2 :(得分:13)
您可以创建以下类:
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");
字段A.s,A.i,A.z将获得新的加载值。
答案 3 :(得分:8)
为什么不使用一个临时实例类,它是静态类的镜像?
[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;
}
}
我知道这有点像黑客攻击,但它实现了相同的目的,同时在运行时仍允许重构,并在运行时进行值验证。
答案 4 :(得分:0)
我发现这个答案对我的设置课程非常有用! 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;
}
}
}
答案 5 :(得分:0)
另一个解决方案,但在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;
}
}