【轉】編寫高品質代碼改善C#程式的157個建議——建議56:使用繼承ISerializable介面更靈活地控制序列化過程

來源:互聯網
上載者:User

標籤:view   create   .com   img   back   繼承   為我   opened   pen   

 

建議56:使用繼承ISerializable介面更靈活地控制序列化過程

介面ISerializable的意義在於,如果特性Serializable,以及與其像配套的OnDeserializedAttribute、OnDeserializingAttribute、OnSerializedAttribute、OnSerializingAttribute、NoSerializable等特性不能完全滿足自訂序列化的要求,那就需要繼承ISerializable了。

 

以下是格式化器的工作流程:如果格式化器在序列化一個對象的時候,發現對象繼承了ISerializable介面,那它就會忽略掉類型所有的序列化特性,轉而調用類型的GetObjectData方法來構造一個SerializationInfo對象,方法內部負責向這個對象添加所有需要序列化的欄位(“添加”這個詞可能不太恰當,因為我們在添加前可以隨意處置這個欄位)。以建議55中的例子為例,如果要為ChineseName構造對應的值,在類繼承ISerializable介面的情況下,應該這樣去實現:

    class Program    {        static void Main()        {            Person liming = new Person() { FirstName = "Ming", LastName = "Li" };            BinarySerializer.SerializeToFile(liming, @"c:\", "person.txt");            Person p = BinarySerializer.DeserializeFromFile<Person>(@"c:\person.txt");            Console.WriteLine(p.FirstName);            Console.WriteLine(p.LastName);            Console.WriteLine(p.ChineseName);                   }    }    [Serializable]    public class Person : ISerializable    {        public string FirstName;        public string LastName;        public string ChineseName;        public Person()        {        }        protected Person(SerializationInfo info, StreamingContext context)        {            FirstName = info.GetString("FirstName");            LastName = info.GetString("LastName");            ChineseName = string.Format("{0} {1}", LastName, FirstName);        }        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)        {            info.AddValue("FirstName", FirstName);            info.AddValue("LastName", LastName);        }    }

序列化工具類:

    public class BinarySerializer    {        //將類型序列化為字串        public static string Serialize<T>(T t)        {            using (MemoryStream stream = new MemoryStream())            {                BinaryFormatter formatter = new BinaryFormatter();                formatter.Serialize(stream, t);                return System.Text.Encoding.UTF8.GetString(stream.ToArray());            }        }        //將類型序列化為檔案        public static void SerializeToFile<T>(T t, string path, string fullName)        {            if (!Directory.Exists(path))            {                Directory.CreateDirectory(path);            }            string fullPath = Path.Combine(path, fullName);            using (FileStream stream = new FileStream(fullPath, FileMode.OpenOrCreate))            {                BinaryFormatter formatter = new BinaryFormatter();                formatter.Serialize(stream, t);                stream.Flush();            }        }        //將字串還原序列化為類型        public static TResult Deserialize<TResult>(string s) where TResult : class        {            byte[] bs = System.Text.Encoding.UTF8.GetBytes(s);            using (MemoryStream stream = new MemoryStream(bs))            {                BinaryFormatter formatter = new BinaryFormatter();                return formatter.Deserialize(stream) as TResult;            }        }        //將檔案還原序列化為類型        public static TResult DeserializeFromFile<TResult>(string path) where TResult : class        {            using (FileStream stream = new FileStream(path, FileMode.Open))            {                BinaryFormatter formatter = new BinaryFormatter();                return formatter.Deserialize(stream) as TResult;            }        }    }
View Code

我們在方法GetObjectData中處理序列化,然後在一個帶參數的構造方法中處理還原序列化。雖然在介面中沒有地方指出需要這樣一個構造器,但這確實是需要的,除非我們序列化後不再打算把它還原序列化回來。

這個例子不能表現出ISerializable介面比Serializable特性的優勢,見下面的例子:

將Person序列化,然後在還原序列化中將其變為另一個對象:PersonAnother類型對象。要實現這個功能,需要Person和PersonAnother都實現ISerializable介面,原來其實很簡單,就是在Person類的GetObjectData方法中處理序列化,在PersonAnother的受保護構造方法中還原序列化。

    class Program    {        static void Main()        {            Person liming = new Person() { FirstName = "Ming", LastName = "Li" };            BinarySerializer.SerializeToFile(liming, @"c:\", "person.txt");            PersonAnother p = BinarySerializer.DeserializeFromFile<PersonAnother>(@"c:\person.txt");            Console.WriteLine(p.Name);        }    }    [Serializable]    class PersonAnother : ISerializable    {        public string Name { get; set; }        protected PersonAnother(SerializationInfo info, StreamingContext context)        {            Name = info.GetString("Name");        }        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)        {        }    }    [Serializable]    public class Person : ISerializable    {        public string FirstName;        public string LastName;        public string ChineseName;        public Person()        {        }        protected Person(SerializationInfo info, StreamingContext context)        {        }        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)        {            info.SetType(typeof(PersonAnother));            info.AddValue("Name", string.Format("{0} {1}", LastName, FirstName));        }    }

在Person類型的GetObjectData方法中,有句代碼非常重要:

info.SetType(typeof(PersonAnother));

它負責告訴序列化器:我要被還原序列化為PersonAnother。而類型PersonAnother則很簡單,它甚至都不需要知道誰會被還原序列化成它,它不需要做任何特殊處理。

ISerializable介面這個特性很重要,如果運用得當,在版本升級中,它能處理類型因為欄位變化而帶來的問題。

 

 

轉自:《編寫高品質代碼改善C#程式的157個建議》陸敏技

【轉】編寫高品質代碼改善C#程式的157個建議——建議56:使用繼承ISerializable介面更靈活地控制序列化過程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.