什么是序列化

WCF 返回XML去除默认命名空间实例Demo WCF 返回XML去除默认命名空间实例Demo 解压后根据说明文档修改您的程序。 立即下载
一、  概述

为什么要序列化一个对象,大概出于两个目的。

第一保存对象以便以后再处理,这是出于对象持久化(persist)的要求。这种情况一般需要把对象保存到可以长久保存的介质上,比如磁盘。保存在磁盘上的数据是一系列连续的字节组成的,所以就需要把对象转换成一个连续的字节串以便把对象写入到磁盘。把一个对象当时的完整状态转换成连续的字节串的过程就是对象的序列化(serialize)过程。反过来把表示一个对象的连续的字节串复原成原来的那个对象的过程就是反序列化(deserialize)过程。

第二,自从有了分布式处理技术后,就出现了需要从一个应用传送一个对象到另一个应用的需求。不同的应用大多数情况是不在同一个机器上的,对象需要在网络上进行传输。跟写入到磁盘类似,网络传输数据也可以看做是传输一个连续的字节串。这种需求同样需要把对象先序列化成连续的字节串,经过网络传输到,到达目标应用,再经过反序列化恢复为对象。

Dotnet framework中针对不同的应用场景提供了几类不同的序列化器,主要有三大类,分别是针对不同的技术提供的。

下面分别介绍三大类一个5个序列化器,每个序列化器都是用一个简单的示例说明把一个对象序列化到一个流,然后再从流反序列化为这个对象。

 

完整的代码(解决方案中包含了本文的所有示例项目)下载地址:DotnetSerialize.rar

 

二、  为remoting提供的BinaryFormatter和SoapFormatter

这两个序列化器都是由System.Runtime.Remoting.Messaging. IRemotingFormatter接口派生。

这两个序列化器是为remoting准备的,remoting是微软在dotnet中提供的应用程序间远程访问的技术,用以替代com+的技术,在通讯通道方面,remoting既支持tcp,也支持http协议,这样就解决防火墙的限制问题。

Remoting技术考虑进行远程访问的双方都是基于dotnet技术的应用,没有太多的考虑使用更通用的业界标准,所以这两个序列化器带有强烈的dotnet的自身特点。

1、 BinaryFormatter和SoapFormatter两个主要特点

1.1.   序列化数据中包含类型信息

对象序列化后的数据中包含类型信息:类的全限定名、版本、区域、KeyToken,所以反序列化时必须制定同一类型,即类的全限定名、版本、区域、KeyToken必须一致,否则会被认为不是同一类型的对象。

1.2.   具有类型保真(type fidelity)的特性

所有的field都将被序列化(包括私有字段),但是不包括属性(属性只是访问器,本身不保存数据),除非field被标记[NonSerialized]属性。

这样序列化后的数据,再被反序列化回对象,将严格的跟原来的对象一模一样。

2、 SoapFormatter

SoapFormatter序列化器把对象序列化为SOAP形式的xml字符串序列,xml形式便于通过HTTP协议在网络上传输,所以remoting在使用HTTP协议时就采用SoapFormatter序列化器序列化对象。

 

SoapFormatter所在名称空间和所在assembly:

Namespace: System.Runtime.Serialization.Formatters.Soap

Assembly: system.runtime.serialization.formatters.soap.dll

 

SoapFormatter序列化器序列化的对象必须是被标记为[Serializable]属性的类。

 

2.1.   准备需要序列化的类

代码很简单,不需要多加说明,有几点需要强调:

l  类必须被[Serializable]属性标记,否则SoapFormatter序列化器序列化时会抛出异常

l  默认类的所有field,不管是公有还是私用的field都会被序列化,以保证类型保真性。除非把某个field标记[NonSerialized]属性。

 

  ///

  /// 需要被序列化的类

  ///

  [Serializable]

  public class book

  {

      //私有field将被序列化

      private string name;

      //构造方法将把下面两个address字段将指向同一个对象

      private string address1;

      private string address2;

      //标识为[NonSerialized]的私有field将被序列化

      [NonSerialized]

      private string address_invisible = "shenzhen";

      //公有field将被序列化

      public string author;

      //属性只是访问器,不被序列化

      public string Name

      {

          get { return name; }

          set { name = value; }

      }

      public book()

      {

          string address = "shenzhen";

          address1 = address;

          address2 = address;

      }

}

2.2.   准备需要序列化的对象和流

序列化时针对对象而言的,是把一个对象的当时的状态完整的转换成连续的字节串。

序列化的源是一个[Serializable]属性类的一个实例对象。

序列化的目标是一个Stream对象,或者是文件流,或者是内存流等等。

所以这一步将要准备需要被序列化的对象和序列化后的目标,一个内存流。

 ///

 ///  声明一个流对象,用来保存序列化后的对象

 ///

 private static MemoryStream myMemoryStream;

 ///

 ///  需要序列化的对象

 ///

 private static book mybook;

 

#region 准备需要序列化的对象

 mybook = new book();

 mybook.Name = "我的第一本书";

 mybook.author = "chnking";

 #endregion

 

 //准备保存序列化后对象的流

 myMemoryStream = new MemoryStream();

 

2.3.   将准备好的对象序列化到准备好的流对象中

使用SoapFormatter对象的Serialize方法进行序列化:

SoapFormatter.Serialize (Stream, Object)

Object 参数是需要被序列化的对象。

Stream是保存序列化后数据的流对象。

这里有几点需要特别强调的:

l  SoapFormatter把对象转换成xml后,从xml到Stream过程默认采用UTF-8编码,而且好像无法改变这个编码。所以,要从Stream转换成字符串需要使用UTF-8进行解码。

l  Serialize方法把对象序列化到Stream对象后,Stream的当前位置在最后,使用 Stream的Read方式读取流中数据注时意把Stream当前位置复位到起始位置。

 

///

/// 将准备好的对象序列化到准备好的流对象中

///

static void Serialize()

{

    //准备序列化器SoapFormatter

    SoapFormatter formatter = new SoapFormatter();

    //序列化mybook对象,序列化到myMemoryStream流对象

    formatter.Serialize(myMemoryStream, mybook);

    #region 将流中的数据转换为字符串或xmlDocument

    byte[] resultByte = myMemoryStream.GetBuffer();

    string resultStr = Encoding.UTF8.GetString(resultByte);

    //转成xmlDocument对象方便在断点调试时查看结果

    XmlDocument myXmlDocument = new XmlDocument();

    myXmlDocument.LoadXml(resultStr);

    #endregion

}

 

2.4.   查看序列化的结果

前面的代码把对象序列化后保存数据的MemoryStream中的数据转换成字符串,然后读入到一个XmlDocument中以方便查看,看一下结果

clip_image002

可以看出以下几点:

l  包含对象的完整的类型信息,包括类的类名、名称空间、版本号、区域、KeyToken,甚至还有所在Assembly的名称,参看上图中的标识。

l  只有field被序列化,不管是私有的还是公有的,除非这个字段被标记[NonSerialized]属性,本例中address_invisible字段就被标记为[NonSerialized],序列化后的结果能看到,address_invisible没有被序列化。

l  对象中几个字段为同一个对象时,在序列化后,只有一个副本,其它的字段指向这个副本。本例中address1字段和address2字段被赋给了同一个字符串对象,在序列化后,address1字段保留了一个副本,address2字段通过引用address1的id来引用这个副本。

2.5.   将流对象中数据反序列化为对象

使用SoapFormatter对象的Deserialize方法进行反序列化

反序列化比较简单,把前面步骤生成的保存序列化后的对象的流直接使用Deserialize方法

///

/// 将Serialize方法序列化到流中的数据反序列化为对象

///

static void Deserialize()

{

    myMemoryStream.Position = 0;

    SoapFormatter formatter = new SoapFormatter();

    mybook = (book)formatter.Deserialize(myMemoryStream);

}

看一下反序列化后得到的对象的状态:

clip_image003

除了被标记为[NonSerialized]的address_invisible字段,这个字段没有被序列化,当然反序列化后的这个字段的值就被丢了,别的字段的状态都被恢复了。

3、 BinaryFormatter

BinaryFormatter序列化器把对象序列化为二进制格式的数据,这样的数据格式最精简、效率最高,但也最不具交互性,适合在局域网内用TCP协议传输,所以remoting在使用TCP协议时就采用BinaryFormatter序列化器序列化对象。

BinaryFormatter在功能上跟SoapFormatter想对应,只是SoapFormatter把对象序列化为Soap形式,BinaryFormatter把对象序列化二进制形式。还有点不同是,SoapFormatter在序列化对象是可以在对象之外增加一些附加信息放入到soap的head部分。

 

BinaryFormatter所在名称空间和所在assembly:

Namespace: System.Runtime.Serialization.Formatters.Binary

Assembly: mscorlib.dll

 

同样BinaryFormatter序列化器序列化的对象必须是被标记为[Serializable]属性的类。

下面的示例还是处理前面SoapFormatter同样的例子,只是把SoapFormatter换成BinaryFormatter看看是什么样的结果。

 

准备需要序列化的类和对象,准备序列化的目标流步骤跟前面SoapFormatter的例一摸一样,参看前面的例子。

 

3.1.   将准备好的对象序列化到准备好的流对象中

使用BinaryFormatter对象的Serialize方法进行序列化:

BinaryFormatter.Serialize (Stream, Object)

这里有几点需要特别强调的:

BinaryFormatter把对象转换成二进制的序列数据,其中总不免会有字符存在,比如字符串类型的字段,对字符同样在序列化过程默认采用UTF-8编码,而且好像无法改变这个编码。

 

///

/// 将准备好的对象序列化到准备好的流对象中

///

static void Serialize()

{

    //准备序列化器BinaryFormatter

    BinaryFormatter formatter = new BinaryFormatter();

    //序列化mybook对象,序列化到myMemoryStream流对象

    formatter.Serialize(myMemoryStream, mybook);

    #region 将流中的数据转换为字符串

    byte[] resultByte = myMemoryStream.GetBuffer();

    string resultStr = Encoding.UTF8.GetString(resultByte);

    #endregion

}

3.2.   查看序列化的结果

序列化的流主要是二进制的数据,不过里面也会夹杂的字符,所以还是使用UTF-8编码把流转成字符串查看。

结果是这样的:

/0/0/0/0????/0/0/0/0/0/0/0/f[1]/0/0/0FBinaryFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/0/0/0&Serialize.BinaryFormatterTest.App+book /0/0/0


name/baddress1/baddress2author [1]/0/0/0
/0/0/0 我的第一本书
/0/0/0/bshenzhen/t
/0/0/0/0/0/0/achnking/v/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0

 


里面乱码部分是二进制的数据,没法看。不过里面的字符还是可以看出些东西来。

“BinaryFormatter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”,这部分是对象的类型的Assembly、版本、区域、KeyToken信息。

“Serialize.BinaryFormatterTest”,这是类所在的名称空间。

“book”,是类型名。

还有其他的field名和他们相关的值,标记为[NonSerialized]的address_invisible字段不会被序列化,所以在这个结果里也没有出现。

3.3.   将流对象中数据反序列化为对象

使用BinaryFormatter对象的Deserialize方法进行反序列化。

跟SoapFormatter一样进行反序列化。

///

/// 将Serialize方法序列化到流中的数据反序列化为对象

///

static void Deserialize()

{

    myMemoryStream.Position = 0;

    BinaryFormatter formatter = new BinaryFormatter();

    mybook = (book)formatter.Deserialize(myMemoryStream);

}

反序列化后得到的对象跟SoapFormatter反序列化的结果一样。

三、  XmlSerializer

XmlSerializer是ASP.NET Web Services使用的序列化器。

Web Services有一系列的业界标准,不只是微软自己的标准, web servces可能跟异构的系统交互,所以,Web Services序列化后的数据只包括对象包含的公有数据,不会包含dotnet的类型信息。

XmlSerializer只转换公共字段和属性,不转换方法、索引、私有字段、只读属性(只读集合除外),XmlSerializer生成的xml的格式受类成员的属性控制,这些属性可以指定类转换成xml后的根节点名称,名称空间,类成员是作为属性形式还是作为节点形式出现等等。

序列化后的数据不包含类型和assembly的信息。

所以XmlSerializer化后得到的xml不是保真的序列化,它只是把对象的一部分公开的数据序列化了,反序列化得到的对象跟原来的对象可能就有些不同了。

 

建立需要通过XmlSerializer序列化的.net类的两种方式:

l  把一般的.net的自定义类型通过添加相应控制xml序列化的属性来建立序列化的类

l  通过工具把现有xml架构生成带有相关属性的.net类,这样的类的对象序列化后将符合这个架构。当希望序列化后的内容遵从某个已知架构时可以使用这种方式构建类。

 

XmlSerializer所在名称空间和所在assembly:

Namespace: System.Xml.Serialization

Assembly: system.xml.dll

 

1、 使用自定义.net类型的序列化

1.1.   定义需要用XmlSerializer序列化的.net类型

自定义个类,这个类要可以通过XmlSerializer序列化器序列化为xml,并且能够根据实际需要控制序列化后的xml的格式。

首先,这个类不需要[Serializable]属性。

其次,用一些Attribute来控制类或类成员如何生成xml。

 

下面是主要的几个Attribute的作用:

1.1.1.   XmlRootAttribute

这个属性必须放在类的前面用来限定需要序列化的类。

[XmlRootAttribute("BOOK", Namespace="http://www.chnking.com", IsNullable = false)]

public class book

{

    //定义类代码

}

属性的第一个参数 ElementName = “BOOK” ,表示序列化后的xml的根元素是BOOK,缺省的话,根元素名就是类名。

参数Namespace,表示根元素的名称空间,这个名称空间是根元素的默认名称空间,表现为:xmlns=”http://www.chnking.com” 这样的形式。

参数IsNullable,值为true时表示如果这个对象实例为Null,生成的xml在根元素的用属性xsi:nil="true"表示。

1.1.2.   XmlAttribute

此属性放在类的公有字段和可读写属性前,表示这个字段或属性在xml中以element的属性形式出现。

[XmlAttribute("Author", Namespace = "http://www.chnkingAttr.com",DataType = "NMTOKEN")]

public string author;

属性的第一个参数AttributeName = "Author",表示这个成员被序列化为Attribute的属性名。

参数Namespace,表示根元素的名称空间,这个名称空间只是这个属性名称空间。

参数DataType,表示这个成员转换为xml的XML Schema类型。一般的,很多XML Schema类型,比如int 、decimal,在.net framework都有相应的数据类型相对应,但也有很多XML Schema类型类型在.net framework中没有,就可以通过[XmlAttribute]的DataType参数来指示转成xml后的XML Schema数据类型。上面的DataType = "NMTOKEN",表示要把.net framework中的string类型转换到XML Schema中的NMTOKEN数据类型。根据W3C XML Schema 中数据类型的定义,NMTOKEN类型中只能包含数字、字母、下划线、冒号,如果不在此范围内的字符都以十六进制的ASCII码表示。比如,如果字符串“^chnking”中包含了NMTOKEN类型不允许出现的^字符,所以这个字符串转成xml后会变成这样:"_x005E_chnking",x005E是字符^的ASCII码。

1.1.3.   XmlElementAttribute

此属性放在类的公有字段和可读写属性前,表示这个字段或属性在xml中以element形式出现。这是XmlSerializer序列化器的默认行为,如果这个公有字段或可读写属性前没有相关Attribute约束,那这个公有字段或可读写属性在序列化后的xml中就以element形式出现。

但是[XmlElementAttribute]还是可以为控制序列化的xml提供更多的控制。

[XmlElementAttribute(ElementName = "NamePro", Namespace = "http://www.chnkingName.com", DataType = "NMTOKEN",IsNullable = true)]

public string Name

{

    get { return name; }

    set { name = value; }

}

属性的第一个参数ElementName = "NamePro",表示这个成员被序列化后element的名称。

第二和第三个参数Namespace和DataType跟上面[XmlAttribute]含义一样。

第四个参数IsNullable = true,这个属性描述相关公有字段或可读写属性的值为null时生成xml的行为。

如果这个属性的值为true,相应的element依然会在序列化后的xml中出现,只是没有值,在element中会有一个xsi:nil="true"属性,表示此元素为null值,比如:

<NamePro xsi:nil="true" xmlns="http://www.chnkingName.com" />

如果这个属性的值为false,相应的element将不会在序列化后的xml中出现。

 

下面是准备需要序列化的类,跟前面两个BinaryFormatter和SoapFormatter中的例子基本上一样。只是改成了适合XmlSerializer的样子:

 [XmlRootAttribute(ElementName = "BOOK", Namespace = "http://www.chnking.com", IsNullable = true)]

public class book

{

    //私有field将不被序列化          

    private string name;

    //构造方法将把下面两个address字段将指向同一个对象

    public string address1;

    public string address2;

    //[XmlAttribute]属性将指示把类的成员序列化为一个element的属性

    [XmlAttribute(AttributeName = "Author", Namespace = "http://www.chnkingAttr.com", DataType = "NMTOKEN")]

    public string author;

    [XmlElementAttribute(ElementName = "NamePro", Namespace = "http://www.chnkingName.com", DataType = "NMTOKEN", IsNullable = true)]

    public string Name

    {

        get { return name; }

        set { name = value; }

    }

    public book()

    {

        string address = "shenzhen";

        address1 = address;

        address2 = address;

    }

}

 

1.2.   准备需要序列化的对象和流

这部分跟BinaryFormatter和SoapFormatter中的例子一样。

不过这里mybook.author属性的值为"^chnking",里面的^符号是author属性被限定为xml的NMTOKEN类型不允许的字符,注意在转换为xml后如何转换这个字符的。

  ///

  ///  声明一个流对象,用来保存序列化后的对象

  ///

  private static MemoryStream myMemoryStream;

  ///

  ///  需要序列化的对象

  ///

  private static book mybook;

      mybook = new book();

      mybook.Name = "我的第一本书";

      mybook.author = "^chnking";

 

 //准备保存序列化后对象的流

 myMemoryStream = new MemoryStream();

 

1.3.   将准备好的对象序列化到准备好的流对象中

跟BinaryFormatter和SoapFormatter不一样,这两个序列化器都有缺省构造函数,XmlSerializer构造函数必须要提供序列化对象的类型参数。

同样也是使用Serialize方法把需要序列化的对象序列化到一个流中。

跟SoapFormatter类似,XmlSerializer把对象转换成xml后,从xml到Stream过程默认采用UTF-8编码,而且好像无法改变这个编码。所以,要从Stream转换成字符串需要使用UTF-8进行解码。

static void Serialize()

{

    //准备序列化器XmlSerializer

    XmlSerializer formatter = new XmlSerializer(typeof(book));

    //序列化mybook对象,序列化到myMemoryStream流对象

    formatter.Serialize(myMemoryStream, mybook);

    #region 将流中的数据转换为字符串或xmlDocument

    byte[] resultByte = myMemoryStream.GetBuffer();

    string resultStr = Encoding.UTF8.GetString(resultByte);

    //转成xmlDocument对象方便在断点调试时查看结果

    XmlDocument myXmlDocument = new XmlDocument();

    myXmlDocument.LoadXml(resultStr);

    #endregion

}

1.4.   查看序列化的结果

前面的代码把对象序列化后保存数据的MemoryStream中的数据转换成字符串,然后读入到一个XmlDocument中以方便查看,看一下结果:

clip_image005

这个结果里面有几点需要注意:

l  类中Author共有字段标识了XmlAttribute属性,,所以它在xml中表现为根元素的一个属性,同时它的值为"^chnking",是NMTOKEN类型,所以字符^被转换成^字符十六进制的ACSII码X005E。

l  公有字段address1和address2是指向同一个对象,跟在BinaryFormatter中address2使用id引用到address1不同,这里这两个字段都被赋给了同一个值。这是因为BinaryFormatter是基于对象的,在序列化成xml依然要体现对象的特性,要反映出序列化前的对象引用关系,而XmlSerializer是面向数据的,它只关心最后形成的数据,所以它不必一定要保留对象直接的引用关系,直接都给他们赋予同一个值。

1.5.   将流对象中数据反序列化为对象

使用XmlSerializer对象的Deserialize方法进行反序列化。

static void Deserialize()

{

    myMemoryStream.Position = 0;

    XmlSerializer formatter = new XmlSerializer(typeof(book));

    mybook = (book)formatter.Deserialize(myMemoryStream);

}

查看反序列化后的对象:

clip_image006

1.6.   测试在web services中序列化对象是否跟XmlSerializer一致

前面讲过,XmlSerializer是dotnet中用于web services序列化对象的序列化器,所以这里就来测试一下在web services中使用前面的那个示例中我们自己用XmlSerializer序列化的对象,看看得到的序列化的结果是不是完全一样。

 

在解决方案中新建一个web services的项目,引用前面XmlSerializer的项目,为了使用项目中定义的需要序列化的那个book类。

Web services的代码很简单:

[WebService(Namespace = "http://chnking.com/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class BookService : System.Web.Services.WebService

{

    [WebMethod]

    public book GetBook()

    {

        book mybook = new book();

        mybook.Name = "我的第一本书";

        mybook.author = "^chnking";

        return mybook;

    }

}

在浏览器中直接浏览这个web services,测试GetBook方法,得到的结果是:

clip_image008

跟前面XmlSerializer例子得到的序列化的结果比较一下,一模一样。

2、 使用工具把现有xml架构转换成.net类

在XmlSerializer这一节的开头我们谈到过,有两种方法建立需要序列化的类。

上面的例子是第一种方式:通过自己写代码定义.net类,然后通过给类成员加上各种Attribute来控制序列化后的xml形式。

还有一种方式是根据给定的xsd 架构文件生成一个.net类,然后这个类序列化后的xml是符合xsd的架构的。

这种方式适合于,在交换数据的双方事先约定了一个交换数据的格式,即先定义了一个schema,双方交换的数据都必须遵从这个schema的情况。

 

2.1.   准备xsd架构文件

还是使用上面的自定义.net的例子数据,根据上面例子序列化后的xml,建立这个xml对应的schema,既前面的xml数据遵从这个schema。

由于xml中Author属性有自己的名称空间,NamePro元素也有自己的名称空间,所以这两个成员需要在单独的schema中定义,所以这个xml一共需要三个schema来定义:

主xsd的内容,文件名test2.xsd,这里面会import Author属性和NamePro元素对应的两个xsd文件,同时把根元素BOOK改成BOOKxsd,生成BOOKxsd的.net类型,跟上个例子的book类型相区别:

xml version="1.0" encoding="utf-16"?>

<xsd:schema xmlns:d1p1="http://www.chnkingAttr.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.chnking.com">

  <xs:import schemaLocation="./test.xsd" namespace="http://www.chnkingAttr.com" />

  <xs:import schemaLocation="./test1.xsd" namespace="http://www.chnkingName.com" />

  <xs:element name="BOOKxsd">

    <xs:complexType>

      <xs:sequence>

        <xs:element name="address1" type="xs:string" />

        <xs:element name="address2" type="xs:string" />

        <xs:element xmlns:q1="http://www.chnkingName.com" ref="q1:NamePro" />

      xs:sequence>

      <xs:attribute ref="d1p1:Author" use="required" />

    xs:complexType>

  xs:element>

xsd:schema>

 

Author属性的schema,文件名test1.xsd:

xml version="1.0" encoding="utf-16"?>

<xs:schema xmlns:tns="http://www.chnkingName.com" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.chnkingName.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="NamePro" type="xs:string" />

xs:schema>

 

NamePro元素schema,文件名test.xsd:

xml version="1.0" encoding="utf-16"?>

<xs:schema xmlns:tns="http://www.chnkingAttr.com" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://www.chnkingAttr.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:attribute name="Author" type="xs:string" />

xs:schema>

 

好了,schema文件都准备好了,使用工具验证一下这些schema生成的一个xml的实例:

<ns0:BOOK ns1:Author="d1p1:Author_0" xmlns:ns1="http://www.chnkingAttr.com" xmlns:ns0="http://www.chnking.com">

  <ns0:address1>address1_0 ns0:address1>

  <ns0:address2>address2_0 ns0:address2>

  <ns2:NamePro xmlns:ns2="http://www.chnkingName.com">NamePro_0 ns2:NamePro>

ns0:BOOK>

 

跟前面示例的xml的模样是一致的,说明这几个schema建立的没有问题。

 

2.2.   根据xsd生成.net类

微软提供了一个工具xsd.exe,它可以根据xsd架构文件,生成相应的.net类,而这个.net类使用XmlSerializer序列化后的xml又能遵从这个xsd架构。

使用下面的命令行生成.net类:

xsd test2.xsd test1.xsd test.xsd /c

命令会产生一个cs文件,里面包含了生成的.net类,这个类如下:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]

[System.SerializableAttribute()]

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.chnking.com")]

[System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.chnking.com", IsNullable=false)]

public partial class BOOKxsd {

    private string address1Field;

    private string address2Field;

    private string nameProField;

    private string authorField;

    public string address1 {

        get {

            return this.address1Field;

        }

        set {

            this.address1Field = value;

        }

    }

    public string address2 {

        get {

            return this.address2Field;

        }

        set {

            this.address2Field = value;

        }

    }

    [System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.chnkingName.com")]

    public string NamePro {

        get {

            return this.nameProField;

        }

        set {

            this.nameProField = value;

        }

    }

    [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://www.chnkingAttr.com")]

    public string Author {

        get {

            return this.authorField;

        }

        set {

            this.authorField = value;

        }

    }

}

 

2.3.   序列化xsd生成的.net类

将xsd生成的.net类,放到前面例子里替代book类,然后序列化,看序列化后的结果:

clip_image010

可以跟前面使用自定义 .net类序列化后的xml对比一下,他们序列化后的xml结果是一样的。

48、住宅抵押贷款支持证券的定价、风险评估与结构化设计 本文深入探讨了住宅抵押贷款支持证券(RMBS)的定价、风险评估与结构化设计。内容涵盖提高定价准确性的方差缩减方法,如准蒙特卡罗序列的应用;分析RMBS面临的利率风险、信用风险和模型风险,并提出相应的度量与应对策略;介绍利用动态规划优化CMO分层结构以最大化发行利润的方法。同时总结了RMBS的基本类型、定价流程及市场发展趋势,为投资者和发行人提供全面的决策支持。 阅读详情

相关推荐

ADS2023实战:2.4GHz超外差接收机从设计到链路预算全流程解析

本文以ADS 2023软件为平台,详细解析了2.4GHz超外差接收机从核心指标定义、架构原理到完整链路搭建与仿真的全流程。通过实战演练,重点阐述了如何利用ADS进行谐波平衡仿真和链路预算分析,以量化评估系统增益、噪声系数等关键性能,为射频工程师提供了一套从理论到仿真的系统级设计方法。

herb5的博客 817

网安学记14 ---- 暴力破解准备

暴力破解

ymy13326056686的博客 878

LEF文件介绍及其生成

介绍LEF文件及其生成方法

weixin_43249158的博客 3万+

pikachu靶场通关之暴力破解

暴力破解 攻击者在不知道目标系统的账号密码的情况下,一种对目标系统尝试性的登录 连续性尝试+字典=自动化 字典 一个有效的字典,可以大大提高暴力破解的效率 字典会在下篇文章分享 如果一个网站没有对登录接口实施防暴力破解的措施,或者实施了不合理的措施。 那么这个网站就存在暴力破解漏洞。 是否要求用户设置了复杂的密码; 是否每次认证都使用安全的验证码; 是否对尝试登录的行为进行判断和限制; 是否在必要的情况下采用了双因素认证; ...等等。 存在暴力破解漏洞的网站可能会遭受暴力破解攻击,但该暴力

qq_51577576的博客 2275

浙大数值分析lab2

最可怕的一道题,题目是这样的 Root of a Polynomial A polynomial of degree nnn has the common form as p(x)=cnxn+cn−1xn−1+⋯+c1x+c0p(x)=c_n x^n + c_{n-1} x^{n-1} + \cdots + c_1 x + c_0p(x)=c​n​​x​n​​+c​n−1​​x​

yao_zou的博客 4796

MT6816角度传感器SPI通信避坑指南:从数据手册到稳定读取的3个关键步骤

本文详细解析了MT6816角度传感器SPI通信中的常见问题与解决方案,包括寄存器地址计算、SPI时序配置和数据校验等关键步骤。通过实测波形和代码示例,帮助工程师避开数据手册中的隐藏陷阱,实现稳定可靠的角度数据读取,特别适用于高精度电机控制场景。

weixin_42520573的博客 517

burpsuite——grep extract暴力破解之结果提取

暴力破解---根据不同数据产生的服务器回复不同进行过滤。

weixin_53324599的博客 1402

Frida实战:如何逆向分析某电商App的doCommandNative函数(附完整Hook脚本)

本文详细介绍了如何使用Frida逆向分析电商App中的doCommandNative函数,涵盖动态注册识别、SO加固对抗及高级Hook脚本编写等实战技巧。通过完整Hook脚本示例,帮助安全研究人员深入理解JNICLibrary的关键函数逆向分析方法,提升移动应用安全研究能力。

weixin_29327977的博客 615

Burp Suite的使用(常用模块)

Burp Suite的使用及其常用模块,抓包、改包、放包,浏览器代理设置

Welcome To My6n Blog 2857

四、ARDUINO UNO开发板介绍

(一)ARDUINO UNO开发板 Arduino生态中包括多种开发板、模块、扩展板。其中UNO R3是最适合入门且功能齐全使用量最多的Arduino开发板。以下就是Arduino UNO R3开发板的图片。 (二)ARDUINO UNO开发板基本构成 Arduino开发板设计得非常简洁,一块AVR单片机、一个晶振或振荡器和一个5V的直流电源。常见的开发板通过一条USB数据线连接计算机。Arduino有各式各样的开发板,其中最通用的是Ardui...

简时刻的博客 7万+

CiteSpace基础操作(CNKI数据的导入分析)(一)

1 Cite Space简单介绍 2 文献导入 2.1 打开知网,选择高级检索

m0_50990607的博客 5万+

Burpsuite【十二模块一次解决】【这都不看?】Filter、Target、Scanner、Proxy、Intruder、Repeater、Sequencer、Decoder、Comparer…

【一个星期成果】Filter、Target、Scanner、Proxy、Intruder、Repeater、Sequencer、Decoder、Comparer、Extender、Project Options、User options

7030

YOLOv8 WIOU

本文介绍了如何在YOLOv8中实现WIOU(Weighted Intersection over Union)的修改方法。主要修改了ultralytics/utils/metrics.py文件中的bbox_iou函数,新增了WIoU_Scale类,支持单调性FM v2、非单调性FM v3两种模式,并提供了动态调整的动量参数。修改后的函数支持多种IoU变体(GIoU、DIoU、CIoU等),通过数学公式实现了更精确的边界框回归损失计算,特别针对小目标检测场景进行了优化。该实现使用了PyTorch框架,包含完整

FJN110的博客 2048

序列化和反序列化

我以前确实对序列化,乃至现在也是不是很熟悉,有时候查找资料,但依旧懵懵懂懂,不过还好遇到一个博主,确定写的挺好的,链接会放再底部 废话不多说,先看官网定义: 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。 序列化主要有两个用途 把对象的字节序列永久保存到硬盘上,通常存放在一个文件中(序列化对象) 在网络上传送对象的字节序列(网络传输对象)

lei_gentle的博客 5万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。

遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题 a,什么叫序列化和反序列化 b,作用。为啥要实现这个 Serializable 接口,也就是为啥要序列化 c,serialVersionUID 这个的值到底是在怎么设置的,有什么用。有的是1L,有的是一长串数字,迷惑ing。 我刚刚见到这个关键字 Serializable 的时候,就有如上的这么些问题。 在处理这...

riemann_的博客 3万+

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

什么是序列化? 如何实现(反)序列化 序列化的应用

1. 什么是序列化与反序列化,什么情况需要序列化1.1 序列化序列化是什么序列化的目的什么情况需要序列化1.2 反序列反序列化是什么反序列化的目的2. Java中的序列化与反序列化2.1 如何实现序列化Java序列化的规定序列化的API实现(反)序列化的示例对象在硬盘上的存储方式2.2 利用序列化,实现深拷贝什么时候不要序列化Java中如何防止序列化 1. 什么是序列化与反序列化,什么情况需要序列化 1.1 序列化 序列化是什么 从百度百科中可以得知,序列化 (Serialization)是将对象的状态信.

qq_43564410的博客 2万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

什么是序列化,为什么要序列化。

转自:网络--(忘记从哪看到的了) 整理:Bob 在学习分布式计算的时候,老师上课提到序列化这个概念。当时有些懵逼,不知道 什么是序列化,下来查了一下,原来在Java里面,序列化就是和Serializable接口相关的 东西。 以下是我从网上找到的关于,什么是序列化,为什么要序列化解释的比较好的一篇博文。 ================================

Bob的博客 4万+

什么是序列化 怎么序列化 为什么序列化

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。 序列化使其他代码可以查看或修改,那些不序列化便无法访问的对象实例数据。确切地说,代码执行序列化需要特殊的权限:即指定了 SerializationFormatter 标志的 Securi...

MARKPAIN的专栏 8555

什么是序列化?序列化的作用是什么?Java 中如何实现序列化和反序列化?

序列化是指将结构化的数据( 例如对象 )转化成一个字符串 / 字节数组。转化过程中,不会造成数据信息部分丢失

m0_69438595的博客 4501

java之序列化与反序列化

序列化与反序列化的理解

m0_73866527的博客 1683

序列化与反序列化

如何理解序列化与反序列化

W_7Vv的博客 2921

序列化、反序列化

因为:Java对象的构造必须先有父对象,才有子对象,反序列化也不例外,所以反序列化时,为了构造父对象,只能调用父类的无参构造函数作为默认的父对象。)是一种将对象以一连串的字节描述的过程,将程序中的对象,放入硬盘(文件)中保存就是序列化,如果不存放在磁盘中,而是一直存放在内存中,会增大内存的消耗;一些敏感的字段,如用户名密码(用户登录时需要对密码进行传输),我们希望对其进行加密,这时,就可以采用本节介绍的方法在客户端对密码进行加密,服务器端进行解密,确保数据传输的安全性。

qq_37432174的博客 8916

关于序列化和反序列化

序列化:将数据结构或对象转换成二进制字节流的过程反序列化:将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程1)transient修饰的变量不能被序列化;2)transient只作用于实现 Serializable 接口;3)transient只能用来修饰普通成员变量字段;

weixin_42888110的博客 1418

Java中的序列化及序列化ID

参考转载自: 秒懂Java序列化与反序列化 Java的序列化ID的作用 1. 定义 Java的序列化:是指把Java对象转换为字节序列的过程 Java的反序列化:是指把字节序列恢复为Java对象的过程 2. 为什么需要 我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的。如何做到呢?这就需要Java序列化与反序列化了。换句话说,一方面,.

三明治文鱼的博客 5841

序列化和反序列化总结

简介 对象的序列化 如上图,我们把一个Person对象以流的方式,写入到文件中保存,叫写对象,也叫对象序列化,对象中包含的不仅仅是字符,使用字节流。 ObjectOutputStream:对象的序列化流 对象序列化的最主要的用处就是在传递,和保存对象(object)的时候,保证对象的完整性和可传递性。 对象的反序列 把文件中保存的对象,以流的方式读取出来,叫做读取对象,也叫对象的反序列。读取的文件保存的都是字节,使用字节流。 ObjectInputStream:对象的反序列流 关于序列化与反序列化,其实就

Venus's Blog 1万+

Java 序列化和反序列化

可以通过实现 readObject 方法来自定义反序列化过程。例如,可以在反序列化时对字段进行额外的验证或初始化。// 不会被默认序列化// 自定义反序列化逻辑// 默认反序列化// 手动反序列化 age// 自定义序列化逻辑// 默认序列化// 手动序列化 age@Override// 序列化// 反序列化。

qq_33807380的博客 1636
上一篇: Berkeley DB——Store Structure 如何存储结构体
下一篇: 最便捷的序列化方式
inter999
博客等级 码龄19年 18粉丝 9原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值