天天看点

.Net组件程序设计之序列化

 .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

.Net组件程序设计之序列化

文件的名称和后缀格式都是自己随便定义的。然后再调用反序列化,获取到之前序列化的对象状态。

<code>1   </code><code>string</code> <code>state = MySerializableCase.BinaryFormattDesSerialize();</code>

<code>2   Console.WriteLine(state);</code>

图2

.Net组件程序设计之序列化

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

.Net组件程序设计之序列化

在反序列化的时候,对象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-&gt;Test"</code><code>;</code>

<code>27         }</code>

<code>28     }</code>

按照上面的调用方式,来看一下结果:

图4

.Net组件程序设计之序列化

这样是在反序列化的时候,如果检测到了实例类型实现了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

.Net组件程序设计之序列化

从结果中就很明显的显示出来了,这里要说几句题外话,细心的朋友可能发现了,在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,如需转载请自行联系原作者

继续阅读