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