【转】编写高质量代码改善C#程序的157个建议——建议54:为无用字段标注不可序列化

 

建议54:为无用字段标注不可序列化

序列化是指这样一种技术:把对象转变成流。相反过程,我们称为反序列化。在很多场合都需要用到这项技术。

  • 把对象保存到本地,在下次运行程序的时候,恢复这个对象。
  • 把对象传到网络中的另外一台终端上,然后在此终端还原这个对象。
  • 其他场合,如:把对象赋值到系统的粘贴板中,然后用快捷键Ctrl+V恢复这个对象。

一下几个原因,决定了要为无用字段标注不可序列化:

  1. 节约了空间。类型在序列化后往往会存储到某个地方,如数据库、硬盘或内存中,如果一个字段在反序列化后不需要保持状态,那它就不应该被序列化,这会占用宝贵的空间资源。
  2. 反序列化后字段信息已经没有意义了。如Windows内核句柄,在反序列化后往往已经失去了意义,所以它就不应该被序列化。
  3. 字段因业务上的原因不允许被序列化。比如,明文密码不应该被序列化后一同保存在文件中。
  4. 如果字段本身所对应的类型在代码中未被设定成可序列化,那它就该被标注不可序列化,否则运行时会抛出SerializationException异常。


类型被添加Serializable特性后,默认所有的字段全部都能被序列化。如果部分字段不需要序列化,可以在该字段上应用NonSerialized特性。属性事实上是方法,所以是不能序列化的,自动属性也是如此。另外,要标识事件为不可序列化,需要用field: NonSerialized语法。

下面是一个序列化工具类:

    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;
            }
        }
    }

实例代码:

    class Program
    {
        static void Main()
        {
            Person mike = new Person() { Age = 21, Name = "Mike" };
            mike.NameChanged += new EventHandler(mike_NameChanged);
            BinarySerializer.SerializeToFile(mike, @"c:\", "person.txt");
            Person p = BinarySerializer.DeserializeFromFile<Person>(@"c:\person.txt");
            p.Name = "Rose";
            Console.WriteLine(p.Name);
            Console.WriteLine(p.Age.ToString());
        }

        static void mike_NameChanged(object sender, EventArgs e)
        {
            Console.WriteLine("Name Changed");
        }
    }

    [Serializable]
    class Person
    {
        private string name;
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                if (NameChanged != null)
                {
                    NameChanged(this, null);
                }
                name = value;
            }
        }

        public int Age { get; set; }

        [NonSerialized]
        private Department department;
        public Department Department
        {
            get
            {
                return department;
            }
            set
            {
                department = value;
            }
        }

        [field: NonSerialized]
        public event EventHandler NameChanged;
    }

输出:

Rose
21

 

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

posted @ 2017-12-06 11:45  指间的徘徊  阅读(485)  评论(0编辑  收藏  举报