zoukankan      html  css  js  c++  java
  • 【转】编写高质量代码改善C#程序的157个建议——建议56:使用继承ISerializable接口更灵活地控制序列化过程

    建议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个建议》陆敏技

  • 相关阅读:
    泛型应用----泛型接口、泛型方法、泛型数组、泛型嵌套
    有选择性的启用SAP UI5调试版本的源代码
    SAP UI5应用入口App.controller.js是如何被UI5框架加载的?
    SAP WebIDE里UI5应用的隐藏文件project.json
    SAP UI5的support Assistant
    如何用SAP WebIDE的Fiori创建向导基于ABAP OData service快速创建UI5应用
    SAP Cloud Platform上Destination属性为odata_gen的具体用途
    Marketing Cloud contact主数据的csv导入
    Marketing Cloud的contact merge机制
    如何让某些用户对Marketing Cloud的contact数据只能实施只读操作
  • 原文地址:https://www.cnblogs.com/farmer-y/p/7991961.html
Copyright © 2011-2022 走看看