SerializableAttribute屬性用於修飾可以序列化的類,如果類支持序列化,便可以使用該屬性來修飾。需要注意的並不是所有支持序列化的類都需要被SerializableAttribute來修飾,只有該類需要或可能需要序列化時,如一些實體類,可能需要持久化或用於進程間傳輸。這樣的對象需要被序列化成字節流或其它便於存儲或傳輸的格式,並且通過這個持久化的格式可以還原或反序列化至內存。凡是使用SerializableAttribute進行修飾的類都可以被諸如System.Runtime.Serialization.Formatters.Binary.BinaryFormatter之類的格式化類進行序列化。如: [csharp] [Serializable] public class Class1 { public string Name { get; set; } public string ID { get; set; } } Class1 cls1 = new Class1(); cls1.Name = "Class1"; cls1.ID = "cls-1"; BinaryFormatter formatter = new BinaryFormatter(); using (FileStream stream = new FileStream("c:\\Class1.bin", FileMode.Create, FileAccess.Write)) { formatter.Serialize(stream, cls1); } using (FileStream stream = new FileStream("c:\\Class1.bin", FileMode.Open, FileAccess.Read)) { Class1 cls2 = formatter.Deserialize(stream) as Class1; } 但如果Class1沒有被SerializableAttribute修飾的話,在formatter.Serialize(stream, cls1)時會拋出SerializationException異常"Type 'XXXX.Class1' in Assembly ..... is not marked as serializable.",因此要想被BinaryFormatter等格式化類序列化,就必須使用SerializableAttribute來修飾。除非你想自己編寫序列化方法,通過反射來序列化對象。 另外,更需要注意的是,所有類,結構,枚舉等都可以使用SerializableAttribute來進行修飾,但不是所有的類或結構都適合序列化,因為有些字段是無法進行序列化的,或無法再反序列化的。如指針(IntPtr類型),因為在我們序列化時,指針地址會被持久化,然而在反序列化時,該指針地址所指向的內容將不在是原來的內容了。除非該指針不需要被序列化,那麼可以使用NonSerializedAttribute來修飾這些不支持序列化的字段。 其實SerializableAttribute僅僅是個標識,用於說明類是可以序列化的。但實際類是否真的合適序列化,需要類的設計者斟酌。設計者需要判斷對象的可序列化的字段中是否包含指針等不合適的類型,因為類的使用者只知道類是SerializableAttribute修飾的,便認為是可以序列化的,僅此而已。 .net framework還提供了一個序列化接口System.Runtime.Serialization.ISerializable,該接口主要用於自定義序列化,並且實現該接口的類也要被SerializableAttribute修飾,才能被BinaryFormatter序列化。ISerializable的使用可以跳過NonSerialized的修飾,並運行你控制序列化和反序列化的過程。示例: [csharp] [Serializable] public class Class1 : ISerializable { public string Name { get; set; } public string ID { get; set; } [NonSerialized] private DateTime BirthDate; public void SetBirthDate(DateTime birthdate) { this.BirthDate = birthdate; } public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Name", this.Name); info.AddValue("ID", this.ID); info.AddValue("BirthDate", this.BirthDate); } public Class1() { } protected Class1(SerializationInfo info, StreamingContext context) { this.Name = info.GetString("Name"); this.ID = info.GetString("ID"); this.BirthDate = info.GetDateTime("BirthDate"); } } [csharp] www.2cto.com BinaryFormatter formatter = new BinaryFormatter(); Class1 cls1 = new Class1(); cls1.Name = "Class1"; cls1.ID = "cls-1"; cls1.SetBirthDate(DateTime.Today); using (FileStream stream = new FileStream("c:\\Class1.bin", FileMode.Create, FileAccess.Write)) { formatter.Serialize(stream, cls1); } Class1 cls2 = null; using (FileStream stream = new FileStream("c:\\Class1.bin", FileMode.Open, FileAccess.Read)) { cls2 = formatter.Deserialize(stream) as Class1; } 實現ISerializable接口的類,還要求類必須實現一個具有(SerializationInfo information, StreamingContext context)簽名的構造函數,該函數為反序列化過程中調用,如果缺少該構造函數,Class1對象在反序列化時將拋出SerializationException異常"The constructor to deserialize an object of type 'XXX.Class1' was not found."。ISerializable接口的聲明: [csharp] [ComVisible(true)] public interface ISerializable { [SecurityCritical] void GetObjectData(SerializationInfo info, StreamingContext context); } ISerializable接口在被Formatter使用時,將會調用GetObjectData方法進行序列化,在反序列化時,將調用類的構造函數(SerializationInfo information, StreamingContext context)。因此如果Class1有子類的話,如Class2,並且Class2也支持序列化,那麼Class2也要實現GetObjectData方法,和(SerializationInfo information, StreamingContext context)簽名的構造函數。如下Class2的定義: [csharp] [Serializable] public class Class2 : Class1 { public int Age { get; set; } public Class2() { } protected Class2(SerializationInfo info, StreamingContext context) : base(info, context) { this.Age = info.GetInt32("Age"); } public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("Age", this.Age); } } 因此實現ISerializable接口時,最後設置GetObjectData方法為virtual的,要有(SerializationInfo information, StreamingContext context)簽名的構造函數,並且該構造函數一般是protected的。