建议57:实现ISerializable的子类型应负责父类的序列化

我们将要实现的继承自ISerializable的类型Employee有一个父类Person,假设Person没有实现序列化,而现在子类Employee却需要满足序列化的场景。不过序列化器并没有默认处理Person类型对象,这些事情只能由我们自己做。

以下是一个不妥的实现,序列化器只发现和处理了Employee中Salary字段:

  1. class Program
  2. {
  3. static void Main()
  4. {
  5. Employee liming = new Employee() { Name = "liming", Salary = };
  6. BinarySerializer.SerializeToFile(liming, @"c:\", "person.txt");
  7. Employee limingCopy = BinarySerializer.DeserializeFromFile<Employee>(@"c:\person.txt");
  8. Console.WriteLine(string.Format("姓名:{0}", limingCopy.Name));
  9. Console.WriteLine(string.Format("薪水:{0}", limingCopy.Salary));
  10. }
  11. }
  12.  
  13. public class Person
  14. {
  15. public string Name { get; set; }
  16. }
  17.  
  18. [Serializable]
  19. public class Employee : Person, ISerializable
  20. {
  21. public int Salary { get; set; }
  22.  
  23. public Employee()
  24. {
  25. }
  26.  
  27. protected Employee(SerializationInfo info, StreamingContext context)
  28. {
  29. Salary = info.GetInt32("Salary");
  30. }
  31.  
  32. public override void GetObjectData(SerializationInfo info, StreamingContext context)
  33. {
  34. info.AddValue("Salary", Salary);
  35. }
  36. }

序列化工具类:

  1. public class BinarySerializer
  2. {
  3. //将类型序列化为字符串
  4. public static string Serialize<T>(T t)
  5. {
  6. using (MemoryStream stream = new MemoryStream())
  7. {
  8. BinaryFormatter formatter = new BinaryFormatter();
  9. formatter.Serialize(stream, t);
  10. return System.Text.Encoding.UTF8.GetString(stream.ToArray());
  11. }
  12. }
  13.  
  14. //将类型序列化为文件
  15. public static void SerializeToFile<T>(T t, string path, string fullName)
  16. {
  17. if (!Directory.Exists(path))
  18. {
  19. Directory.CreateDirectory(path);
  20. }
  21. string fullPath = Path.Combine(path, fullName);
  22. using (FileStream stream = new FileStream(fullPath, FileMode.OpenOrCreate))
  23. {
  24. BinaryFormatter formatter = new BinaryFormatter();
  25. formatter.Serialize(stream, t);
  26. stream.Flush();
  27. }
  28. }
  29.  
  30. //将字符串反序列化为类型
  31. public static TResult Deserialize<TResult>(string s) where TResult : class
  32. {
  33. byte[] bs = System.Text.Encoding.UTF8.GetBytes(s);
  34. using (MemoryStream stream = new MemoryStream(bs))
  35. {
  36. BinaryFormatter formatter = new BinaryFormatter();
  37. return formatter.Deserialize(stream) as TResult;
  38. }
  39. }
  40.  
  41. //将文件反序列化为类型
  42. public static TResult DeserializeFromFile<TResult>(string path) where TResult : class
  43. {
  44. using (FileStream stream = new FileStream(path, FileMode.Open))
  45. {
  46. BinaryFormatter formatter = new BinaryFormatter();
  47. return formatter.Deserialize(stream) as TResult;
  48. }
  49. }
  50. }

输出为:

姓名:
薪水:2000

看见,Name字段并没有正确处理。这需要我们修改类型Employee中受保护的构造方法GetObjectData方法,为它加入父类字段的处理:

  1. [Serializable]
  2. public class Employee : Person, ISerializable
  3. {
  4. public int Salary { get; set; }
  5.  
  6. public Employee()
  7. {
  8. }
  9.  
  10. protected Employee(SerializationInfo info, StreamingContext context)
  11. {
  12. Name = info.GetString("Name");
  13. Salary = info.GetInt32("Salary");
  14. }
  15.  
  16. public void GetObjectData(SerializationInfo info, StreamingContext context)
  17. {
  18. info.AddValue("Name", Name);
  19. info.AddValue("Salary", Salary);
  20. }
  21. }

修改后输出:

姓名:liming
薪水:2000

上面的例子中Person类未被设置成支持序列化。现在,假设Person类已经实现了ISerializable接口,那么这个问题处理起来会相对容易,在子类Employee中,我们只需要调用父类受保护的构造方法和GetObjectData方法就可以了。如下所示:

  1. [Serializable]
  2. public class Person : ISerializable
  3. {
  4. public string Name { get; set; }
  5.  
  6. public Person()
  7. {
  8. }
  9.  
  10. protected Person(SerializationInfo info, StreamingContext context)
  11. {
  12. Name = info.GetString("Name");
  13. }
  14.  
  15. public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  16. {
  17. info.AddValue("Name", Name);
  18. }
  19. }
  20.  
  21. [Serializable]
  22. public class Employee : Person, ISerializable
  23. {
  24. public int Salary { get; set; }
  25.  
  26. public Employee()
  27. {
  28. }
  29.  
  30. protected Employee(SerializationInfo info, StreamingContext context)
  31. : base(info, context)
  32. {
  33. Salary = info.GetInt32("Salary");
  34. }
  35.  
  36. public override void GetObjectData(SerializationInfo info, StreamingContext context)
  37. {
  38. base.GetObjectData(info, context);
  39. info.AddValue("Salary", Salary);
  40. }
  41. }

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

编写高质量代码改善C#程序的157个建议——建议57:实现ISerializable的子类型应负责父类的序列化的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  2. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  3. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  4. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  5. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

  6. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  7. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  8. 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释

    建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...

  9. 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量

    建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...

  10. 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法

    建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...

随机推荐

  1. Chrome 的审查元素功能有哪些奇技淫巧

    学习地址: https://www.zhihu.com/question/34682699

  2. 新机器连接老机器遇到的ERROR

    Ansible无法连接老旧机器 报错内容: [root@BI ansible]# ansible -i /etc/ansible/hosts GameServer -m ping 10.10.113. ...

  3. Linux环境下安装XAMPP的PHP的PDF扩展

    安装pdf扩展1. wget http://pecl.php.net/get/pdflib-4.1.2.tgz2. tar zxvf pdflib-4.1.2.tgz3. cd pdflib-4.1. ...

  4. php中的continue用法

    continue 2 表示跳出两层 continue 默认跳出一层 if (count($content_arr) > 0 ) { // 获取相应的goods数据 $goodsdata = ar ...

  5. CGI/MIME/servlet术语解释

    CGI→一种协议, 一种标准, 一种规范 使用CGI协议, 能够让用户访问某些动态资源的时候, 触发web服务器, 让web服务器根据CGI协议能够调用外部(web服务器外部)的程序来执行处理这个动态 ...

  6. mysql枚举类型与集合类型

    枚举类型与集合类型 字段的值只能在给定范围中选择,如单选框,多选框 enum 单选 只能在给定的范围内选一个值,如性别 sex 男male/女female set 多选 在给定的范围内可以选择一个或一 ...

  7. Py修行路 python基础 (十五)面向对象编程 继承 组合 接口和抽象类

    一.前提回忆: 1.类是用来描述某一类的事物,类的对象就是这一类事物中的一个个体.是事物就要有属性,属性分为 1:数据属性:就是变量 2:函数属性:就是函数,在面向对象里通常称为方法 注意:类和对象均 ...

  8. springboot成神之——ioc容器(依赖注入)

    springboot成神之--ioc容器(依赖注入) spring的ioc功能 文件目录结构 lang Chinese English GreetingService MyRepository MyC ...

  9. windows Server 2008各版本有何区别?

    windows Server 2008有几个版本,先一一列出来把: Windows Server 2008 Standard Edition     (标准版) Windows Server 2008 ...

  10. 如何使用Visual Studio2015进行C++项目创建

    打开Visual Studio 2015,点击程序左上角的“文件”--“新建”--“项目”. 在弹出窗口选择模板“visual C++”,在新建项目栏里选择“win32控制台应用程序”,直接点击确定. ...