序列化和反序列化
序列化将内存中的对象变成一个序列用以传输或保存,反序列化反之。在配置管理中,需要将一个包含配置信息的对象序列化保存到xml格式的配置文件中或根据配置文件还原生成配置对象。
序列化和反序列化应用的场合很多,因此微软支持多种方式的序列化和反序列化,其中就包括将一个对象序列化保存成一个xml文件并可反序列化的方法。
1 .net提供的序列化工具:XmlSerializer
序列化示例代码:
XmlSerializer xs=new XmlSerializer(typeof(person));
Stream stream = new FileStream("c://cyj.xml", FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
xs.Serialize(stream, c);
stream.Close();
反序列化示例代码:
XmlSerializer ser = new XmlSerializer(typeof(Person));
System.IO.FileStreamfs = new System.IO.FileStream("c://cyj.xml ",FileMode.Open);
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(fs);
Person person = (Person)(ser.Deserialize(reader));
在上述示例中person就是要被序列化的对象。关于这方面的代码很多,大家可以在网上搜搜。
2 自定义序列化方法
除了微软提供的现成的方法来进行序列化和反序列化之外,在某些情况下,我们可能需要对序列化的过程进行控制,这就需要我们自定义序列化方法,这并不难!其中的关键是我们要明白序列化的实质是根据对象的类型信息将该对象保存成一个序列,而这其中的关键就是如何获取对象的类型信息!幸运的是微软为我们提供了获取一个对象类型信息的途径:
Reflection
(反射)。
在.net的命名空间System.Reflection下,定义了多个集合用于保存一个对象类型的属性、字段、方法、接口等信息,运用这些信息,我们可以轻而易举地获取一个对象的各种信息,从而将他序列化。
下面是我写的一个将一个对象序列化的方法源代码:
///
<summary>
///
将一个对象序列化并保存到一个文件中
///</summary>
///<param name="obj">
被序列化的对象
</param>
///<param name="file">
保存的文件路径
</param>
///<returns></returns>
private void Serialize(object obj,string file)
{
Type customDataType =obj.GetType();
Stream xmlfile = new FileStream(file, FileMode.Create, FileAccess.Write);
string TAB =" ";
StreamWriter sw = new StreamWriter(xmlfile);
sw.WriteLine("<?xml version=/"1.0/"?>");
sw.WriteLine("<"+customDataType.Name +" xmlns:xsd=/"http://www.w3.org/2001/XMLSchema/" xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/">");
//
写入对象的属性信息
System.Reflection.PropertyInfo[] paraInfos = customDataType.GetProperties();
foreach(System.Reflection.PropertyInfo pi in paraInfos)
{
if(pi.PropertyType.IsArray==false)
{
sw.WriteLine(TAB+"<"+pi.Name+">"+pi.GetValue(obj,null).ToString()+"</"+pi.Name+">");
}
else
{
sw.WriteLine(TAB+"<"+pi.Name+">");
Array fivalue = (Array)pi.GetValue(obj,null);
for(int i=0;i<fivalue.Length;i++)
{
object item = fivalue.GetValue(i);
Type itemtype = item.GetType();
sw.WriteLine(TAB+TAB+"<"+itemtype.ToString()+">"+item.ToString()+"</"+itemtype.ToString()+">");
}
sw.WriteLine(TAB+"</"+pi.Name+">");
}
}
//
写入对象的字段信息
System.Reflection.FieldInfo[] filedInfos = customDataType.GetFields();
foreach(System.Reflection.FieldInfo fi in filedInfos)
{
if(fi.FieldType.IsArray==false)
{
sw.WriteLine(TAB+"<"+fi.Name+">"+fi.GetValue(obj).ToString()+"</"+fi.Name+">");
}
else
{
sw.WriteLine(TAB+"<"+fi.Name+">");
Array fivalue = (Array)fi.GetValue(obj);
for(int i=0;i<fivalue.Length;i++)
{
object item = fivalue.GetValue(i);
Type itemtype = item.GetType();
sw.WriteLine(TAB+TAB+"<"+itemtype.ToString()+">"+item.ToString()+"</"+itemtype.ToString()+">");
}
sw.WriteLine(TAB+"</"+fi.Name+">");
}
}
sw.WriteLine("</"+customDataType.Name+">");
sw.Flush();
sw.Close();
xmlfile.Close();
}
在上述代码中,只序列化了对象的属性和字段信息,并考虑了属性或字段为简单类型数组的情况,其他复杂情况没有考虑,大家可以根据实际情况进行完善!
反序列化的源代码如下:
private object DeSerialize(Type type,string file)
{
XmlDocument xd = new XmlDocument();
try
{
xd.Load(file);
}
catch
{
return null;
}
object returnobj = System.Activator.CreateInstance(type);
if(returnobj==null)
{
return null;
}
//
设置对象的值
XmlNode RootNode = xd.DocumentElement;
foreach(XmlNode xn in RootNode.ChildNodes)
{
if(xn.ChildNodes.Count>1)//
是数组
{
int index=0;
object[] subnodeArray = new object[xn.ChildNodes.Count];
foreach(XmlNode subnode in xn.ChildNodes)
{
subnodeArray[index]=subnode.InnerText;
index++;
}
object setvalue = (object)subnodeArray;
SetValue(ref returnobj,xn.Name,setvalue);
}
else//
不是数组
{
object setvalue = (object)xn.InnerText;
SetValue(ref returnobj,xn.Name,setvalue);
}
}
return returnobj;
}
在上述代码中,用到了下面两个方法:
///<summary>
///
设置一个对象的属性的值
///</summary>
///<param name="obj">
对象
</param>
///<param name="name">
属性名
</param>
///<param name="setvalue">
属性值
</param>
///<returns></returns>
private string SetValue(ref object obj,string name,object setvalue)
{
Type type = obj.GetType();
System.Reflection.PropertyInfo[] paraInfos = type.GetProperties();
foreach(System.Reflection.PropertyInfo pi in paraInfos)
{
if(pi.PropertyType.IsArray==false)
{
if(pi.Name==name)
{
pi.SetValue(obj,Convert.ChangeType(setvalue,pi.PropertyType),null);
}
}
}
//
写入对象的字段信息
System.Reflection.FieldInfo[] filedInfos = type.GetFields();
foreach(System.Reflection.FieldInfo fi in filedInfos)
{
if(fi.FieldType.IsArray==false)
{
if(fi.Name==name)
{
fi.SetValue(obj,Convert.ChangeType(setvalue,fi.FieldType));
}
}
else
{
if(fi.Name==name)
{
System.Array vaArray= (System.Array) setvalue;
Type elementType = fi.FieldType.GetElementType();
for(int i =0;i<vaArray.Length;i++)
{
object element = InstantiateAndFill(elementType,vaArray.GetValue(i));
type.InvokeMember(fi.Name,
BindingFlags.SetField,
null,
obj,
new Object[] {i, element},
null,
null,
null);
}
}
}
}
return "";
}
private Object InstantiateAndFill(Type t,object val)
{
if(val==null)
{
return null;
}
Random r= new Random(); // one time
Object instance= null;
try
{
// special case a few types
switch (t.FullName)
{
case "System.String":
{
instance= val.ToString();
}
break;
case "System.Object":
instance= val;
break;
case "System.Boolean":
instance= bool.Parse(val.ToString());
break;
case "System.Single":
instance= (Object) System.Single.Parse(val.ToString());
break;
case "System.DateTime":
instance= (Object) DateTime.Parse(val.ToString());;
break;
case "System.Decimal":
instance= (Object) Decimal.Parse(val.ToString());
break;
case "System.Int32":
instance= (object)int.Parse(val.ToString());
break;
default:
break;
}
}
catch(System.Exception e)
{
MessageBox.Show("Exception in InvokeMember("+t.Name+":"+e.Message);
}
return instance;
}
上述代码只是我对自定义序列化方法的一个尝试,其中有不成熟的地方,希望大家根据自己的需要完善它!
上述代码都是在.net Framework 1.1下运行通过,其他没有测试。