现在的位置: 首页 > 综合 > 正文

.NET 序列化与反序化

2011年01月06日 ⁄ 综合 ⁄ 共 6445字 ⁄ 字号 评论关闭
文章目录

序列化与反序化目的是为了解决对象的传递与持久化操作,如在不同的进程,应用程序哉,服务间传递,对象的保存与状态还原.

      .net 环境下提供的序列化方式至3.5版本,有二进制,SOAP,XML,DataContract,JavaScript等,开源的有如Json.net等。当然也有自己手动反射实现的,比如利用MemberInfo,或者FormatterServices (二进制,SOAP等方式是封装了FormatterServices 的操作)。以上的几中方式处理序列化的对象都有不同的要求,二进制,SOAP,XML方式要求对象必须属性标记可序列化[Serializable],而DataContract,JavaScript则虽然没有强制这种要求,但是Serializable,NonSerialized,OnSerializing,OnDeserialized等属性标记仍然在DataContract,JavaScript格化器执行中有效。

ps:序列化与反序列化的对象是原对象的副本,并不是引用。封送传值的对象是要求必须可序列化的。

PS:属性标记 Attribute 在编译时是直接构建带构造参数的Attribute的实例写入元数据及IL中。所以在反射获取的都是Attribute的实例。可以通过Type.IsDefined判断是否标记过属性,这种效率最高。当然还可以通过GetCustomAttribute(获取实例并可以操作)/GetCustomAttributeData(只获取反射实例,但不操作)

     在序列化和反序化的过程,可以对序列化过程做一些其它特殊处理操作。看下面示例的注释

 [Serializable]
private class Demo {

[NonSerialized]
private string name;
public string Name
{
get { return name; }
set { name = value; }
}

[OnSerializing] //被序列化时会执行的方式 解决一些特殊的情况处理
private void OnSerializing(StreamingContext context) { }
[OnSerialized] //序列化完成后会调用的方法 解决一些特殊的情况处理
private void OnSerialized(StreamingContext context) { }

[OnDeserializing] //被反序列化时会执行的方式 解决一些特殊的情况处理
private void OnDeserializing(StreamingContext context) { }
[OnDeserialized] //被反序列化完成后执行的方式 解决一些特殊的情况处理
private void OnDeserialized(StreamingContext context) { }
}

 

 1.微软提供直接实现序列化与反序列化的实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Xml.Serialization;
using System.Web;

namespace EFTool.Test
{
///<summary>
/// 序列化与反序列化帮助类(二进制,SOAP,XML,DataContract格式化操作类)
/// SOAP在3.5以后废弃,取而代之尽量使用XmlSerializer,DataContractSerializer.
/// 流格式化可以选择多种方式如FileStream,MemoryStream等
/// 封送传值的对象要求必须可序列化标记(副本),而封送引用的对象可以通过继承MarshalbyRefObject(代理)
///</summary>
public static class SerializationHelper
{
#region 二进制方式 对象必须标记为Serializable
///<summary>
/// 以二进制序列化对象(不必知道对象的具体类型)
///</summary>
///<param name="graph">对象必须标记为Serializable</param>
///<returns></returns>
public static Stream SerializeByBinary(object graph)
{
MemoryStream memoryStream = new MemoryStream();
IRemotingFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, graph); //已完成序列化到流中( 此处我们借助其它的流格式,比如说FileStream 将序列化数据转至文件中)
//Byte[] arrGraph = memoryStream.ToArray(); //将序列化的结果转换为64位字符串 (转成字符串类型后,可以将数据存至数据库中其传至其它地方)
return memoryStream;

}

///<summary>
/// 反序列化以二进制方式
///</summary>
///<typeparam name="T"></typeparam>
///<param name="graph"对象必须标记为Serializable></param>
///<returns></returns>
public static T DeserializeByBinary<T>(Stream stream)
{
stream.Position = 0;
IRemotingFormatter formatter = new BinaryFormatter();
return (T)formatter.Deserialize(stream);
}
#endregion

#region 二进制深度复制克隆 StreamingContextStates.Clone 对象必须标记为Serializable
///<summary>
/// 以二进制序列化对象(不必知道对象的具体类型)
///</summary>
///<param name="graph"></param>
///<returns></returns>
public static Stream DeepCloneSerializeByBinary(object graph)
{
MemoryStream memoryStream = new MemoryStream();
IRemotingFormatter formatter = new BinaryFormatter();
//深度复制
formatter.Context = new StreamingContext(StreamingContextStates.Clone);
formatter.Serialize(memoryStream, graph);
return memoryStream;

}

///<summary>
/// 反序列化以二进制方式
///</summary>
///<typeparam name="T"></typeparam>
///<param name="graph"></param>
///<returns></returns>
public static T DeepCloneDeserializeByBinary<T>(Stream stream)
{
stream.Position = 0;
IRemotingFormatter formatter = new BinaryFormatter();
formatter.Context = new StreamingContext(StreamingContextStates.Clone);
return (T)formatter.Deserialize(stream);
}
#endregion

#region SOAP方式(过时) 对象必须标记为Serializable
///<summary>
/// 以SOAP序列化对象(不必知道对象的具体类型)
///</summary>
///<param name="graph"></param>
///<returns></returns>
public static Stream SerializeBySoap(object graph)
{
MemoryStream memoryStream = new MemoryStream();
IRemotingFormatter formatter = new SoapFormatter();
formatter.Serialize(memoryStream, graph);
return memoryStream;

}

///<summary>
/// 反序列化以SOAP方式
///</summary>
///<typeparam name="T"></typeparam>
///<param name="graph"></param>
///<returns></returns>
public static T DeserializeBySoap<T>(Stream stream)
{
stream.Position = 0;
IRemotingFormatter formatter = new SoapFormatter();
return (T)formatter.Deserialize(stream);
}
#endregion

#region XML方式 取代SOAP->不能处理复杂对象 对象必须标记为Serializable
///<summary>
/// 以XML序列化(XML序列化的对象中包含集合类属性可能会引发异常,XML序列对集合类属性序列化有特殊要求)
///</summary>
///<typeparam name="T"></typeparam>
///<param name="graph"></param>
///<returns></returns>
public static Stream SerializeByXml<T>(object graph)
{
MemoryStream memoryStream = new MemoryStream();
XmlSerializer formatter = new XmlSerializer(typeof(T));
formatter.Serialize(memoryStream, graph);
return memoryStream;
}

///<summary>
/// 字符串反序列化对象(XML)
///</summary>
///<typeparam name="T"></typeparam>
///<param name="graph"></param>
///<returns></returns>
public static T DeserializeByXml<T>(Stream stream)
{
stream.Position = 0;
XmlSerializer formatter = new XmlSerializer(typeof(T));
return (T)formatter.Deserialize(stream);
}

#endregion

#region DataContractSerialzer方式 对象不必标记为Serializable
///<summary>
/// DataContractSerialzer序列化对象
///</summary>
///<typeparam name="T"></typeparam>
///<param name="graph"></param>
///<returns></returns>
public static Stream SerializeByDataContract<T>(object graph)
{
MemoryStream memoryStream = new MemoryStream();
DataContractSerializer formatter = new DataContractSerializer(typeof(T));
formatter.WriteObject(memoryStream,graph);
return memoryStream;
}

///<summary>
/// DataContractSerialzer反序列化对象
///</summary>
///<typeparam name="T"></typeparam>
///<param name="graph"></param>
///<returns></returns>
public static T DeserializeByDataContract<T>(Stream stream)
{
stream.Position = 0;
DataContractSerializer formatter = new DataContractSerializer(typeof(T));
return (T)formatter.ReadObject(stream);
}
#endregion

}

}

 

利用FormatterServices反射实现(同MemberInfo类似)

 BlogCategory cate = new BlogCategory();
cate.CateID = 1;
cate.CateName = "llj";
cate.CreateTime = DateTime.Now;
cate.SortID = 10;
cate.BlogArticle.Add(new BlogArticle()
{
UserID=20,
ArticleID = 1,
BlogCategory_CateID = 1,
Title = "love",
CreateTime = DateTime.Now

});

//获取字段成员及对应的值
MemberInfo[] members = FormatterServices.GetSerializableMembers(cate.GetType());
object[] membersValues = FormatterServices.GetObjectData(cate, members);

for (int i = 0; i < members.Length; i++)
{
//构建序列化的二进制数据或者XML/JSON等,当然自己要处理大量复杂的业务
//members[i].Name
//membersValues[i]
}

//反序化为对象
BlogCategory cate2 = (BlogCategory)FormatterServices.GetUninitializedObject(typeof(BlogCategory));
//BlogCategory cate2 = new BlogCategory();
FormatterServices.PopulateObjectMembers(cate2, members, membersValues);

当然这是一种便捷的方式,也可以通过手动反射实现,要手动实现就得考虑性能与复杂类型的处理问题。比如碰到导航类,或者泛型集合,而Nullable<T>这种泛型值类型通常用以处理非空值类型也会被误认为泛型集合。上一节介绍的CLR几种反射性能的例子 都可以实现同样的目的。

 

 

抱歉!评论已关闭.