|
原著:matthew reynold (www.asptoday.com)
翻译整理:51dotnet 俱乐部 会员:lookuptable 本文得分:2000
(译者注:本文介绍了.net中xml serialization的概念和一个相应的简单的例子,同时也涉及了很多.net中比较重要的概念,如stream,reflection,服务器端控件的使用等,虽然并没有很详细地说明xml serialization的实际用途,但我们也可以从文章和它的例子中得到很多启示。本文所带的例子用vs.net打开时可能会有问题,所以最好是按照本文的讲述自己创建一个例子,以加深理解)
在本文中,我们将一起了解一下xml的序列化(serialization)。它是这样一个过程:得到一个对象,把对象转换为一个xml文档,并且保存它以供使用,或者把它传到网络上其他地方以供使用。在.net中,xml serialization通过检查类的属性是否被标志为read/write来工作。只要有其中一个属性,该类的值就会被取出并插入到一个xml文档里去。反序列化(de-serialization)则是一个相反的过程。

毫无疑问,.net可以很方便的使用xml。在.net中,使用xml serialization需要做的就是把对象转化为一块xml,然后把它当作“流”(stream)传出去。随着对.net的了解,你将会发现“流”这个比喻很贴切。比如如果要向磁盘写一个文件,需要打开一个文件流;也可以通过打开了一个网络流发送字节到另一台机器上。“流”的方法很简捷并且可以用在.net开发中的很多方面,一旦你知道了一种“流”的使用办法,那么你就会很容易的掌握其他的使用方法。
.net framework中的xml serialization
当第一次看到xml serialization的时候,我觉得它看起来很复杂。把一个对象转换为一个xml块,需要实例化一个xmlserializer对象并把要转换的对象传给他。同样,把一个xml块转换为一个对象,我们也需要用xmlserializer,只是这次我们需要传入一个xml而不是对象。
多数情况下,你不必对要做序列化(serialize)的对象作任何改动。xmlserializer检查对象的属性,并假设对象中任何可以read/write的属性都应该被包括在序列化过程中。然后它将像一个典型的客户程序一样调用这些属性。
比如如果你的对象实现了一个read/write的属性叫做name,那么xmlserializer将调用该属性并把返回值插入到xml块中。当用xmlserializer从一个xml块建立一个对象时,它将取出保存在xml块中的值并将其设置为对象的属性值。(这个过程是通过reflection实现的,我们在后面会谈到)
作为一个典型的开发人员,当我第一次看到xml serialization时,我觉得并不是很舒服。因为我觉得这就像个杂牌电脑一样。我认为它的过程应该是这样的:比如,xmlserializer应该调用一个接口中的方法,该方法要求我提供需要插入到xml中的信息。事实上这的确是system.runtime.serialization名字空间中的iserializable接口所做的工作。而实现iserializable并不麻烦,相反使用xmlserializer却是很繁琐的事。
直到现在,我已经对xml serialization有了很长时间的了解,我认识到它的功能确实很强大而且很值得去使用。对一个有经验的开发者来说,不用担心对其缺少控制,xml serialization为我们提供了一个很快捷的方法可以把对象压成一个流然后再把他们抽出来。
reflection
对于没有接触过的人来说,你会看到reflection是一个很强大的功能,在这个过程里,.net framework中的任何对象可以被检查并且可以决定它的属性,方法和事件。任何.net中的对象都是从object类中派生出来的,object类包含了一个叫做gettype的方法,这个方法返回一个system.type类型的对象,这个对象包含了一些方法如getproperties和getmethods,他们可以用来得到更多的关于对象的信息。
xmlserializer简单的调用getproperties方法返回一个propertyinfo对象数组,数组中每一个值都描述了对象的一个属性。如果属性是read/write的,它就可以被包含在序列化中。
asptoday中有专门关于reflection的文章,此外如果感兴趣的话,你也可以在其他地方找到相关的资料。当然你也可以自己试一下framework sdk中的clsview例子。reflection中最让人头疼的地方是emitting功能,它让你可以在运行时创建一个类然后在你的程序中使用这个类,就好像他们是正常的类一样。
测试序列化
为了测试一下我们的序列化,我们需要一个应用程序,其中应该包含一个用来转化为xml的类,并且可以再转化回来。我们用vb.net/asp.net来做,首先创建一个新的visual basic – web application项目,针对本文,项目命名为serialization,如果看一下代码,你会发现这会是一个很好的名字
为了显示结果,我们在项目中创建一个包括一个text area的web form。我们要使用一个叫book的对象,该对象包括name, isbn number以及author列表等属性。这个text area将用来显示由xmlserializer产生的xml。 然后我们还可以修改产生的xml并且通过这个xml创建一个新的对象。(比如我们可以通过public beta把书的标题从beginning e-commerce改成vb .net programming)。一旦我们得到了新的对象,我们要用一个简单的服务器端控件处理一下这个对象并显示。
创建form
首先我们需要创建一个form,打开aspx页面的html视图做以下修改:
<%@ page language="vb" autoeventwireup="false" codebehind="webform1.vb"
inherits="serialization.webform1"%>
<html><head>
<meta name="generator" content="microsoft visual studio .net 7.0">
<meta name="code_language" content="visual basic 7.0"></head>
<body>
<form id="webform1" method="post" runat="server">
<textarea runat="server" id="xmlarea" cols="60" rows="15"></textarea>
<br>
<input runat="server" type="submit" value="turn xml into an object!">
</form>
</body></html> |
请注意我们把text area元素的id属性设置为xmlarea。这将允许我们在vb代码中操纵该元素。通常我们用value属性来得到或者设置元素所包含的文本内容。如果运行页面,我们可以得到以下结果:

vs.net的开发环境中有个问题:尽管我们已经把text area加入到页面中了,但有时候对xmlarea的引用并不会加入到webform1类的定义中。如果没有这个引用,我们将不能使用和处理该字段,因此我们也不能得到或者设置它的值。如果你打开webform1.vb的代码,应该可以看到下面这样的代码行
public class webform1
inherits system.web.ui.page
protected withevents xmlarea as system.web.ui.htmlcontrols.htmltextarea |
如果这一行不在,那么你自己加上它。
创建book类
我们要使用的类叫做book。开始我们先简单的使用类中的name和isbn属性。这里没什么特殊的,所以创建一个叫做book的新类。
imports system
imports system.collections
public class book
private m_name as string
private m_isbn as string
public property name() as string
get
return m_name
end get
set
m_name = value
end set
end property
public property isbn() as string
get
return m_isbn
end get
set
m_isbn = value
end set
end property
end class
|
处理prerender
在处理输出页面上的窗体前,我们要确定xmlarea字段中包含了xml块。因此我们需要创建一个book类的实例,设置name和isbn属性的默认值并调用xmlserializer来序列化该对象。
当然我们需要先把对xmlserializer的引用加到我们的项目中来。在solution explorer中,右击reference并选择add reference。找到system.xml.serialization.dll,选中点击ok。

在使用对象前,我们需要在webform1.vb的顶部再加上必要的引用:
imports system
imports system.componentmodel.design
imports system.data
imports system.drawing
imports system.web
imports system.web.sessionstate
imports system.web.ui
imports system.web.ui.webcontrols
imports system.web.ui.htmlcontrols
imports microsoft.visualbasic
imports system.io
imports system.xml.serialization |
在ide中打开webform1.vb,从左上角选择对象,拖放,实例化webform1对象,从右边的列表中选择prerender方法。把下面的代码加入其中来检查我们是否能够从xmlarea中得到值:
public sub webform1_prerender(byval sender as object, _
byval e as system.eventargs) handles webform1.prerender
if we dont already have a value, create a default book…
if xmlarea.value = "" then |
如果form已经被提交,xmlarea中将有一个值。其中会包含用户想加入的任何信息。接下来我们创建一个book对象的实例并且设置属性值:
create an instance of a book…
dim mybook as new book()
mybook.name = "beginning e-commerce"
mybook.isbn = "1861003986"
接下来我们需要一个system.io.tex |
twriter,xmlserializer会把数据产生给它。一个textwriter通常用来提供对数据流的访问,比如一个磁盘文件或者网络连接。在我们的例子中,我们使用system.io.textwriter。这是一个textwriter对象,表示字符串中已经存在的部分,不论何时新的数据加入都会被连接到已存在数据的末尾。
create a new string writer…
dim writer as new stringwriter() |
接着我们创建xmlserializer对象,这需要我们要进行序列化的事物的type对象了。一旦有了这个,我们要求它来把对象序列化为stringwriter对象。
[table][tr][td] create a serializer…
dim serializer as new xmlserializer(mybook.gettype)
serializer.serialize(writer, mybook)
最后我们可以用stringwriter的tostring方法得到xml块的内容,我们把text area元素的value值设成该字符串:
set the value in the form…
xmlarea.value = writer.tostring
end if
end sub |