首 页 网络编程
网页制作 图形图象 操作系统 冲浪宝典
软件教学 认证考试

网络安全 网络办公 行业资讯 评测对比
您当前位置:站长天空 -> 软件教学-> 压缩工具
.Net里的序列化-.NET教程,Asp.Net开发
作者:网友供稿 点击:49
推荐
西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!可在线rar解压,自动数据恢复设置虚拟目录等.免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金
站内搜索
文章页数:[1] 
什么是序列化?
---.net的运行时环境用来支持用户定义类型的流化的机制。它是将对象实例的状态存储到存储媒体的过程。在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流。在随后对对象进行反序列化时,将创建出与原对象完全相同的副本。

序列化的目的:
1、以某种存储形式使自定义对象持久化;
2、将对象从一个地方传递到另一个地方。

实质上序列化机制是将类的值转化为一个一般的(即连续的)字节流,然后就可以将该流写到磁盘文件或任何其他流化目标上。而要想实际的写出这个流,就要使用那些实现了iformatter接口的类里的serialize和deserialize方法。
在.net框架里提供了这样两个类:

一、binaryformatter

binaryformatter使用二进制格式化程序进行序列化。您只需创建一个要使用的流和格式化程序的实例,然后调用格式化程序的 serialize 方法。流和要序列化的对象实例作为参数提供给此调用。类中的所有成员变量(甚至标记为 private 的变量)都将被序列化。

首先我们创建一个类:
[serializable]
public class myobject {
public int n1 = 0;
public int n2 = 0;
public string str = null;
}
serializable属性用来明确表示该类可以被序列化。同样的,我们可以用nonserializable属性用来明确表示类不能被序列化。
接着我们创建一个该类的实例,然后序列化,并存到文件里持久:
myobject obj = new myobject();
obj.n1 = 1;
obj.n2 = 24;
obj.str = "一些字符串";
iformatter formatter = new binaryformatter();
stream stream = new filestream("myfile.bin", filemode.create,
fileaccess.write, fileshare.none);
formatter.serialize(stream, obj);
stream.close();

而将对象还原到它以前的状态也非常容易。首先,创建格式化程序和流以进行读取,然后让格式化程序对对象进行反序列化。
iformatter formatter = new binaryformatter();
stream stream = new filestream("myfile.bin", filemode.open,
fileaccess.read, fileshare.read);
myobject obj = (myobject) formatter.deserialize(fromstream);
stream.close();

// 下面是证明
console.writeline("n1: {0}", obj.n1);
console.writeline("n2: {0}", obj.n2);
console.writeline("str: {0}", obj.str);

二、soapformatter

前面我们用binaryformatter以二进制格式来序列化。很容易的我们就能把前面的例子改为用soapformatter的,这样将以xml格式化,因此能有更好的可移植性。所要做的更改只是将以上代码中的格式化程序换成 soapformatter,而 serialize 和 deserialize 调用不变。对于上面使用的示例,该格式化程序将生成以下结果。

<soap-env:envelope
xmlns:xsi=http://www.w3.org/2001/xmlschema-instance
xmlns:xsd="http://www.w3.org/2001/xmlschema"
xmlns:soap- enc=http://schemas.xmlsoap.org/soap/encoding/
xmlns:soap- env=http://schemas.xmlsoap.org/soap/envelope/
soap-env:encodingstyle=
"http://schemas.microsoft.com/soap/encoding/clr/1.0
http://schemas.xmlsoap.org/soap/encoding/"
xmlns:a1="http://schemas.microsoft.com/clr/assem/tofile">

<soap-env:body>
<a1:myobject id="ref-1">
<n1>1</n1>
<n2>24</n2>
<str id="ref-3">一些字符串</str>
</a1:myobject>
</soap-env:body>
</soap-env:envelope>

在这里需要注意的是,无法继承 serializable 属性。如果从 myobject 派生出一个新的类,则这个新的类也必须使用该属性进行标记,否则将无法序列化。例如,如果试图序列化以下类实例,将会显示一个 serializationexception,说明 mystuff 类型未标记为可序列化。

public class mystuff : myobject
{
public int n3;
}

然而关于格式化器,还有个问题,假设我们只需要xml,但不需要soap特有的额外信息,那么该怎么做?有两个方案:1、编写一个实现iformatter接口的类,采用的方式类似于soapformatter,但是可以没有你不需要的信息;2、使用框架提供的类xmlserializer。
xmlserializer类和前两个主流的序列化类的几个不同点是:
1、不需要serializable属性,serializable和nonserializable属性将会被忽略,但是使用xmlignore属性,和nonserializable属性类似。
2、该类不能安全地访问私有变成员,所以学要将私有成员改为公共成员,或者提供合适的公共特性。
3、要求被序列化的类要有一个默认的构造器。

我们改一下前面的myobject类为:

public class myobject {
public int n1;
public string str;
public myobject(){}
public myobject(n1,str)
{
this.n1=n1;
this.str=str;
}
public override string tostring()
{
return string.format("{0}:{1}",this.str,this.n1);
}
}

现在我们用xmlserializer类来对修改后的myobject进行序列化。因为xmlserializer类的构造器里有个type参数,所以xmlserializer对象被明确的 连到该type参数所表示的类了。xmlserializer类也有serialize和deserialize方法:
myobject obj = new myobject(12,"some string...");
xmlserializer formatter = new xmlserializer(typeof(myobject));
stream stream = new filestream("myfile.xml", filemode.create,
fileaccess.write, fileshare.none);
formatter.serialize(stream, obj);
//下面是反序列化
stream.seek(0,seekorigin.begin)
myobject obj_out=(myobject)formatter.deserialize(stream)
stream.close();
console.writeline(obj_out);

这个简单的列子可以加以扩展,以便利用更多的xmlserializer功能,包括使用属性控制xml标记、使用xml模式和进行soap编码。

自定义序列化

如果你希望让用户对类实现序列化,但是对数据流的组织方式不完全满意,那么可以通过在对象上实现 iserializable 接口来自定义序列化过程。这一功能在反序列化后成员变量的值失效时尤其有用,但是需要为变量提供值以重建对象的完整状态。除了必须将类申明为 serializable 的同时,还要要实现 iserializable接口,需要实现 getobjectdata 方法以及一个特殊的构造函数,在反序列化对象时要用到此构造函数。在实现 getobjectdata 方法时,最常调用的serializationinfo的方法是addvalue,这个方法具有针对所有标准类型(int、char等等)的重载版本;而 streamingcontext 参数描述给定的序列化流的源和目标,这样我们就可以知道我们是将对象序列化到持久性存储还是在将他们跨进程或机器序列化。而在反序列化时,我们调用serializationinfo提供的一组getxxx方法,他们针对所有标准类型数据执行各种addvalue重载版本的逆操作。下代码示例说明了如何在前一部分中提到的 myobject 类上实现 iserializable。

[serializable]
public class myobject : iserializable
{
public int n1;
public int n2;
public string str;

public myobject()
{
}

protected myobject(serializationinfo info, streamingcontext context)
{
n1 = info.getint32("i");
n2 = info.getint32("j");
str = info.getstring("k");
}

public virtual void getobjectdata(serializationinfo info,
streamingcontext context)
{
info.addvalue("i", n1);
info.addvalue("j", n2);
info.addvalue("k", str);
}
}
在序列化过程中调用 getobjectdata 时,需要填充方法调用中提供的 serializationinfo 对象。只需按名称/值对的形式添加将要序列化的变量。其名称可以是任何文本。只要已序列化的数据足以在反序列化过程中还原对象,便可以自由选择添加至 serializationinfo 的成员变量。如果基对象实现了 iserializable,则派生类应调用其基对象的 getobjectdata 方法。

需要强调的是,将 iserializable 添加至某个类时,需要同时实现 getobjectdata 以及特殊的具有特定原型的构造函数--重要的是,该构造函数的参数列表必须与getobjectdata相同,这个构造函数将会在反序列化的过程中使用:格式化器从流中反序列化数据,然后通过这个构造函数对对象进行实列化。如果缺少 getobjectdata,编译器将发出警告。但是,由于无法强制实现构造函数,所以,缺少构造函数时不会发出警告。如果在没有构造函数的情况下尝试反序列化某个类,将会出现异常。在消除潜在安全性和版本控制问题等方面,当前设计优于 setobjectdata 方法。例如,如果将 setobjectdata 方法定义为某个接口的一部分,则此方法必须是公共方法,这使得用户不得不编写代码来防止多次调用 setobjectdata 方法。可以想象,如果某个对象正在执行某些操作,而某个恶意应用程序却调用此对象的 setobjectdata 方法,将会引起一些潜在的麻烦。

在反序列化过程中,使用出于此目的而提供的构造函数将 serializationinfo 传递给类。对象反序列化时,对构造函数的任何可见性约束都将被忽略,因此,可以将类标记为 public、protected、internal 或 private。一个不错的办法是,在类未封装的情况下,将构造函数标记为 protect。如果类已封装,则应标记为 private。要还原对象的状态,只需使用序列化时采用的名称,从 serializationinfo 中检索变量的值。如果基类实现了 iserializable,则应调用基类的构造函数,以使基础对象可以还原其变量。

如果从实现了 iserializable 的类派生出一个新的类,则只要新的类中含有任何需要序列化的变量,就必须同时实现构造函数以及 getobjectdata 方法。以下代码片段显示了如何使用上文所示的 myobject 类来完成此操作。

[serializable]
public class objecttwo : myobject
{
public int num;

public objecttwo() : base(){ }

protected objecttwo(serializationinfo si, streamingcontext context) : base(si,context)
{
num = si.getint32("num");
}

public override void getobjectdata(serializationinfo si, streamingcontext context)
{
base.getobjectdata(si,context);
si.addvalue("num", num);
}
}
切记要在反序列化构造函数中调用基类,否则,将永远不会调用基类上的构造函数,并且在反序列化后也无法构建完整的对象。

对象被彻底重新构建,但是在反系列化过程中调用方法可能会带来不良的副作用,因为被调用的方法可能引用了在调用时尚未反序列化的对象引用。如果正在进行反序列化的类实现了 ideserializationcallback,则反序列化整个对象图表后,将自动调用 onserialization 方法。此时,引用的所有子对象均已完全还原。有些类不使用上述事件侦听器,很难对它们进行反序列化,散列表便是一个典型的例子。在反序列化过程中检索关键字/值对非常容易,但是,由于无法保证从散列表派生出的类已反序列化,所以把这些对象添加回散列表时会出现一些问题。因此,建议目前不要在散列表上调用方法。


文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

文章页数:[1] 


放大字体显示 缩小字体显示 打印文章 推荐给朋友
热门文章
·web打印的另类方法-ASP教程,打印相关
·Java简单类型进行精确浮点数运算-JSP教程,Java技巧及代码
·使用JAVAMAIL发邮件的一个例子-JSP教程,邮件相关
·中国移动本地传输网建设方案初探
·传输系统中的时钟同步技术
·JSP学习经验总结(转)-JSP教程,Jsp/Servlet
·WEB打印,去页眉和页脚-ASP教程,打印相关
·Native XML数据库技术详解-.NET教程,XML应用
·jsp生成html--readtemplates-JSP教程,Jsp/Servlet
·下拉框反回选定的文字 (修改页面经常用到)-ASP教程,ASP应用
最新文章
·在xp中如何使用windows vista屏保_windows xp
·photoshop调色:cmyk模式处理单色调特效_photoshop教程
·视频分享网站视频广告发展面临的问题_营销推广
·难以置信,这样的网站每月盈利上千万_营销推广
·大站做百度主题推广 小站做google adsense_网赚技巧
·方兴东:保留alexa插件才能给站长带来快乐_站长访谈
·网友天下ceo叶灵:欢迎大家看web2.0笑话_站长访谈
·我们应该如何运营网站_站长心得
·网站从业者还要更加务实才能赚钱_站长心得
·炼成高级网络编辑的三大原则_站长心得
相关主题
  • .net里动态生成控件数组-.NET教程,组件控件开发
  • .NET里面的Interop太烂了-.NET教程,.NET Framework
  • .Net里的哈希表和串行化-.NET教程,评论及其它
  • .net里面的数值格式变换-.NET教程,Asp.Net开发
  • 西部数码虚拟主机

    友情链接
    CNNIC 西部数码
    万网 自助建站
    虚拟主机 asp空间
    域名注册 域名
    域名申请 主页空间
    论坛空间 网站空间
    国际域名 虚拟空间
    空间租用 DDOS防火墙
    成都主机托管 四川主机托管
    主机租用 服务器租用
    网站目录 自助建站
    虚拟主机 网址大全
    软件下载
    自助链接
    虚拟主机资讯 特价虚拟主机
    版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!
    关于我们:站长天空:专业提供最新的站长资讯、在线教程、虚拟主机权威评测、虚拟主机性能对比、网站制作教程,开发教程,站长工具。包括网页制作教程、冲浪宝典、编程参考、操作系统、软件教学、行业动态等。
    特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
    发表评论 打印  刷新     关闭