.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,如需轉載請自行聯系原作者