.Net组件程序设计之序列化
自动序列化
Serializable属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<code> </code><code>1 [Serializable]</code>
<code> </code><code>2 </code><code>public</code> <code>class</code> <code>SerializableCase</code>
<code> </code><code>3 </code>
<code> </code><code>4 {</code>
<code> </code><code>5 </code>
<code> </code><code>6 </code><code>public</code> <code>SerializableCase() { }</code>
<code> </code><code>7 </code>
<code> </code><code>8 </code><code>private</code> <code>string</code> <code>_State;</code>
<code> </code><code>9 </code>
<code>10 </code><code>public</code> <code>string</code> <code>State</code>
<code>11 </code>
<code>12 {</code>
<code>13 </code>
<code>14 </code><code>get</code> <code>{ </code><code>return</code> <code>_State; }</code>
<code>15 </code>
<code>16 </code><code>set</code> <code>{ _State = value; }</code>
<code>17 </code>
<code>18 }</code>
<code>19 </code>
<code>20 }</code>
在上面的示例类型上加上Serializable属性这样将示例类型标记为可序列化类型.
21
22
23
24
25
<code> </code><code>1 </code><code>public</code> <code>class</code> <code>MySerializableCase</code>
<code> </code><code>2 {</code>
<code> </code><code>3 </code><code>public</code> <code>static</code> <code>void</code> <code>BinaryFormatterSerialize()</code>
<code> </code><code>4 {</code>
<code> </code><code>5 IFormatter formatter = </code><code>new</code> <code>BinaryFormatter();</code>
<code> </code><code>6 Stream stream = </code><code>new</code> <code>FileStream(</code><code>"jin.glory"</code><code>, FileMode.Create, FileAccess.ReadWrite);</code>
<code> </code><code>7 </code><code>using</code> <code>(stream)</code>
<code> </code><code>8 {</code>
<code> </code><code>9 SerializableCase serCase = </code><code>new</code> <code>SerializableCase();</code>
<code>10 serCase.State = </code><code>"Test"</code><code>;</code>
<code>11 formatter.Serialize(stream, serCase);</code>
<code>12 }</code>
<code>13 }</code>
<code>14 </code>
<code>15 </code><code>public</code> <code>static</code> <code>void</code> <code>BinaryFormatterDesSerialize()</code>
<code>16 {</code>
<code>17 Stream stream = </code><code>new</code> <code>FileStream(</code><code>"jin.glory"</code><code>, FileMode.Open, FileAccess.Read);</code>
<code>18 IFormatter formatter = </code><code>new</code> <code>BinaryFormatter();</code>
<code>19 </code><code>using</code> <code>(stream)</code>
<code>20 {</code>
<code>21 SerializableCase serCase = formatter.Deserialize(stream) </code><code>as</code> <code>SerializableCase;</code>
<code>22 </code><code>return</code> <code>serCase.State;</code>
<code>23 }</code>
<code>24 }</code>
<code>25 }</code>
BinaryFormattSerialize()方法里只是实例化SerializableCase类型,然后对State属性赋值,代表一个状态。调用 MySerializableCase.BinaryFormattSerialize()后.NET把序列化好的文件流保存到了jin.glory文件中.
图1

文件的名称和后缀格式都是自己随便定义的。然后再调用反序列化,获取到之前序列化的对象状态。
<code>1 </code><code>string</code> <code>state = MySerializableCase.BinaryFormattDesSerialize();</code>
<code>2 Console.WriteLine(state);</code>
图2
SoapFormatter是在命名空间System.Runtime.Serialization.Formatters.Soap下的(在System.Runtime.Serialization.Formatters.Soap.dll中)
<code> </code><code>1 </code><code>public</code> <code>class</code> <code>MySerializableCase</code>
<code> </code><code>3 </code><code>public</code> <code>static</code> <code>void</code> <code>SoapFormatterSerialize()</code>
<code> </code><code>5 IFormatter formatter = </code><code>new</code> <code>SoapFormatter();</code>
<code> </code><code>6 Stream stream = </code><code>new</code> <code>FileStream(</code><code>"Soap.xml"</code><code>, FileMode.Create, FileAccess.ReadWrite);</code>
<code>15 </code><code>public</code> <code>static</code> <code>string</code> <code>SoapFormatterDesSerialize()</code>
<code>17 Stream stream = </code><code>new</code> <code>FileStream(</code><code>"Soap.xml"</code><code>, FileMode.Open, FileAccess.Read);</code>
<code>18 IFormatter formatter = </code><code>new</code> <code>SoapFormatter();</code>
和上面的二进制格式化器使用的方式近乎相同,唯一不同的是,使用Soap格式化器生成的序列化文件耗时更长,占用空间也比较大,但是它是遵循着SOAP协议的,这在跨平台操作数据间是很有用的,平台只需要解析重建就能把对象重新的生成出来。
26
27
28
29
30
31
32
<code> </code><code>3 {</code>
<code> </code><code>4 </code><code>public</code> <code>SerializableCase() { }</code>
<code> </code><code>6 </code><code>private</code> <code>string</code> <code>_State;</code>
<code> </code><code>8 </code><code>public</code> <code>string</code> <code>State</code>
<code> </code><code>9 {</code>
<code>10 </code><code>get</code> <code>{ </code><code>return</code> <code>_State; }</code>
<code>11 </code><code>set</code> <code>{ _State = value; }</code>
<code>12 }</code>
<code>14 [NonSerialized]</code>
<code>15 </code><code>private</code> <code>DonotSerializable _DonotSerializable;</code>
<code>16 </code>
<code>17 </code><code>public</code> <code>DonotSerializable DonotSerializable</code>
<code>18 {</code>
<code>19 </code><code>get</code> <code>{ </code><code>return</code> <code>_DonotSerializable; }</code>
<code>20 </code><code>set</code> <code>{ _DonotSerializable = value; }</code>
<code>21 }</code>
<code>22 }</code>
<code>23 </code><code>public</code> <code>class</code> <code>DonotSerializable</code>
<code>24 {</code>
<code>25 </code><code>public</code> <code>DonotSerializable() { }</code>
<code>26 </code>
<code>27 </code><code>public</code> <code>string</code> <code>DonotSerializableData</code>
<code>28 {</code>
<code>29 </code><code>get</code><code>;</code>
<code>30 </code><code>set</code><code>;</code>
<code>31 }</code>
<code>32 }</code>
修改了一下第一段的示例代码,增加了个属性,并且设置其字段为NonSerialized,这样在.NET序列化这个类的实例的时候,检测到了[NonSerialized]的时候就会跳过它,因为有的对象确实是不适合序列化来进行持久化的,不过这样的做的也会有个问题,就是对象的状态丢失,就是不可序列化的部分会丢失。看一下下面的代码:
<code>11 serCase.DonotSerializable = </code><code>new</code> <code>DonotSerializable();</code>
<code>12 serCase.DonotSerializable.DonotSerializableData = </code><code>"DonotSerializableData"</code><code>;</code>
<code>13 formatter.Serialize(stream, serCase);</code>
<code>14 }</code>
<code>15 }</code>
<code>17 </code><code>public</code> <code>static</code> <code>string</code> <code>BinaryFormatterDesSerialize()</code>
<code>19 Stream stream = </code><code>new</code> <code>FileStream(</code><code>"jin.glory"</code><code>, FileMode.Open, FileAccess.Read);</code>
<code>20 IFormatter formatter = </code><code>new</code> <code>BinaryFormatter();</code>
<code>21 </code><code>using</code> <code>(stream)</code>
<code>22 {</code>
<code>23 SerializableCase serCase = formatter.Deserialize(stream) </code><code>as</code> <code>SerializableCase;</code>
<code>24 </code><code>return</code> <code>serCase.State+</code><code>"_"</code><code>+serCase.DonotSerializable.DonotSerializableData;</code>
<code>25 }</code>
<code>26 }</code>
<code>27 }</code>
修改了上面的二进制格式器的代码,调用一下测试代码我们一起来看下结果:
<code>1 MySerializableCase.BinaryFormatterSerialize();</code>
<code>2 </code><code>string</code> <code>state = MySerializableCase.BinaryFormatterDesSerialize();</code>
<code>3 Console.WriteLine(state);</code>
图3
在反序列化的时候,对象SerializableCase的DonotSerializable属性丢失了,所以才会报错。
对于这样的情况,.NET提供了IDeserializationCallback接口,它里面只有一个函数void OnDeserialization(object sender),只要实现了IDeserializationCallback,并且在OnDeserialization函数里实现具体的对不可序列化对象的初始化。
<code> </code><code>2 </code><code>public</code> <code>class</code> <code>SerializableCase:IDeserializationCallback</code>
<code>22 </code>
<code>23 </code><code>public</code> <code>void</code> <code>OnDeserialization(</code><code>object</code> <code>sender)</code>
<code>24 {</code>
<code>25 _DonotSerializable = </code><code>new</code> <code>DonotSerializable();</code>
<code>26 _DonotSerializable.DonotSerializableData = </code><code>"DonotSerializableData->Test"</code><code>;</code>
<code>27 }</code>
<code>28 }</code>
按照上面的调用方式,来看一下结果:
图4
这样是在反序列化的时候,如果检测到了实例类型实现了IDeserializationCallback接口,是在反序列化完成的时候会执行实现了IDeserializationCallback的OnDeserialization()方法,这样可以对一些不可序列化的属性状态在这个方法里来实现。
.NET2.0
引进了对序列化事件的支持,当序列化和反序列化的时候,.NET在你的类上调用指定的方法,.NET中定义了四个序列化和反序列化事件。
serializing事件是在序列化发生之前被触发,
serialized 事件是在序列化之后被触发,
deserializing事件是在反序列化之前被触发,
deserialized事件是在反序列化之后被触发。
引用先前的示例代码SerializableCase类的初始代码:
<code> </code><code>[Serializable]</code>
<code> </code><code>public</code> <code>class</code> <code>SerializableCase </code><code>//:IDeserializationCallback</code>
<code> </code><code>{</code>
<code> </code><code>public</code> <code>SerializableCase() { }</code>
<code> </code><code>private</code> <code>string</code> <code>_State;</code>
<code> </code><code>public</code> <code>string</code> <code>State</code>
<code> </code><code>{</code>
<code> </code><code>get</code> <code>{ </code><code>return</code> <code>_State; }</code>
<code> </code><code>set</code> <code>{ _State = value; }</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
添加了事件后的示例代码是这样的:
33
34
35
36
37
38
39
<code> </code><code>2 </code><code>public</code> <code>class</code> <code>SerializableCase </code>
<code> </code><code>5 </code><code>private</code> <code>string</code> <code>_State;</code>
<code> </code><code>6 </code><code>public</code> <code>string</code> <code>State</code>
<code> </code><code>7 {</code>
<code> </code><code>8 </code><code>get</code> <code>{ </code><code>return</code> <code>_State; }</code>
<code> </code><code>9 </code><code>set</code> <code>{ _State = value; }</code>
<code>10 }</code>
<code>12 [OnSerializing]</code>
<code>13 </code><code>private</code> <code>void</code> <code>OnSerializing(StreamingContext context)</code>
<code>14 {</code>
<code>15 _State = </code><code>"此时的状态是:序列化之前"</code><code>;</code>
<code>16 Console.WriteLine(State);</code>
<code>17 }</code>
<code>18 </code>
<code>19 [OnSerialized]</code>
<code>20 </code><code>private</code> <code>void</code> <code>OnSerialized(StreamingContext context)</code>
<code>21 {</code>
<code>22 _State = </code><code>"此时的状态是:序列化之后"</code><code>;</code>
<code>23 Console.WriteLine(State);</code>
<code>25 </code>
<code>26 [OnDeserializing]</code>
<code>27 </code><code>private</code> <code>void</code> <code>OnDeserializing(StreamingContext context)</code>
<code>29 _State = </code><code>"此时的状态是:反序列化之前"</code><code>;</code>
<code>30 Console.WriteLine(State);</code>
<code>32 </code>
<code>33 [OnDeserialized]</code>
<code>34 </code><code>private</code> <code>void</code> <code>OnDeserialized(StreamingContext context)</code>
<code>35 {</code>
<code>36 _State = </code><code>"此时的状态是:反序列化之后"</code><code>;</code>
<code>37 Console.WriteLine(State);</code>
<code>38 }</code>
<code>39 }</code>
使用之前定义好的MySerializableCase类型中的静态方法,稍作修改来演示一下,
<code> </code><code>1 </code><code>public</code> <code>static</code> <code>void</code> <code>SoapFormatterSerialize()</code>
<code> </code><code>2 {</code>
<code> </code><code>3 IFormatter formatter = </code><code>new</code> <code>SoapFormatter();</code>
<code> </code><code>4 Stream stream = </code><code>new</code> <code>FileStream(</code><code>"Soap.xml"</code><code>, FileMode.Create, FileAccess.ReadWrite);</code>
<code> </code><code>5 </code><code>using</code> <code>(stream)</code>
<code> </code><code>6 {</code>
<code> </code><code>7 SerializableCase serCase = </code><code>new</code> <code>SerializableCase();</code>
<code> </code><code>8 formatter.Serialize(stream, serCase);</code>
<code> </code><code>9 }</code>
<code>11 </code><code>public</code> <code>static</code> <code>string</code> <code>SoapFormatterDesSerialize()</code>
<code>13 Stream stream = </code><code>new</code> <code>FileStream(</code><code>"Soap.xml"</code><code>, FileMode.Open, FileAccess.Read);</code>
<code>14 IFormatter formatter = </code><code>new</code> <code>SoapFormatter();</code>
<code>15 </code><code>using</code> <code>(stream)</code>
<code>16 {</code>
<code>17 SerializableCase serCase = formatter.Deserialize(stream) </code><code>as</code> <code>SerializableCase;</code>
<code>18 </code><code>return</code> <code>serCase.State;</code>
<code>19 }</code>
<code>20 </code>
测试代码:
<code>1 MySerializableCase.SoapFormatterSerialize();</code>
<code>2 MySerializableCase.SoapFormatterDesSerialize();</code>
<code>3 Console.ReadLine();</code>
图5
从结果中就很明显的显示出来了,这里要说几句题外话,细心的朋友可能发现了,在SerializableCase类型中的四个事件函数签名都是相同的,这是因为在.NET中为这个这个序列化和反序列化事件定义的委托就是这个签名,在这个类型实例序列化和反序列化的时候会检测到.NET会反射实例内部所有的函数 检测是否有附加了序列化事件,如果判断了有则会继续检查这个函数的签名,如果函数签名也匹配了,就会把这个函数挂上委托。
可以这样指定一个函数为事件指定调用函数:
<code>1 [OnSerializing]</code>
<code>2 [OnSerialized]</code>
<code>3 [OnDeserializing]</code>
<code>4 [OnDeserialized]</code>
<code>5 </code><code>private</code> <code>void</code> <code>OnGenericSerializEventMethod(StreamingContext context)</code>
<code>6 {</code>
<code>7 ……</code>
<code>8 }</code>
本篇幅序列化内容结束。
本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1421957,如需转载请自行联系原作者