持久化(persistence)是类型的一个重要特性。只要我们的类型不是UI控件、窗体或者表单,都应该尽可能的为类型添加序列化支持。.NET的序列化是把类中所有成员变量保存到输出流中,同时.NET的序列化还支持任意的对象图(object graph):即使你的对象上有一个循环引用,serialize 和deserialize 方法都只会为你的实际对象读取和储存一次。
1. .NET的序列化支持
在.NET中支持序列化是一件非常简单的任务,在绝大多数的情况下,只需要添加一个Serializable特性就可以了。但是这里有一个前提:
使用Serializable特性对类进行序列化支持,要求该类的所有成员都是可序列化的。
例如,下面的例子,由于int和string类型都是支持.NET序列化,所有我们只需要简单的添加Serializable特性即可。
1 [Serializable] 2 public class MyType 3 { 4 private string lable; 5 private int value; 6 }
反之,如果在一个类中如果有成员不支持序列化,而又使用Serializable,例如下面的代码中,由于OhterClass类没有序列化支持,在序列化MyType时,会得到一个运行时错误。
1 [Serializable] 2 public class MyType 3 { 4 private string lable; 5 private int value; 6 private OtherClass other; 7 }
2.正确的初始化使用NonSerialized特性的成员
添加Serializable特性是支持对象序列化的最简单方式,但最简单的方式却不一定总是这却的方式。假如:我们并不想序列化对象的所有成员:比如某些成员可能只存在于与长期操作的缓存中、或者占用着一些运行时资源,而这些资源只存在于与内存中时我们该如何解决这一问题呢?同样,我们可以通过添加NonSerialized特性到任何你不想让它序列化的数据成员上:
1 [Serializable] 2 public class MyClass 3 { 4 public int Id{get;set;} 5 [NonSerialized] 6 public int CachedValue{get;set;} 7 public string Name{get;set;} 8 }
当我们使用NonSerialized特性时,我们同时也需要完成一些额外的工作:因为在反序列化的过程中.NET序列化API不会初始化使用NonSerialized特性的成员,同时由于类型的构造函数不会被调用,所有成员的初始化器也就不会被执行。当使用Serializable特性时,那些使用NonSerialized特性的成员只会得到系统设定的默认值:0或null(值类型或引用类型);如果系统默认的初始化行为并不是我们想要的效果,那么着时候我们可以通过实现IDeserializationCallback接口来对这些成员进行初始化。在整个对象图被反序列化之后,.NET会自动调用该接口唯一的OnDeserialization()方法。