C# 运行时序列化

一. 序列化与反序列的作用

为什么要有序列化呢,考虑下面这种情况,在WINFORM或者更为方便的WPF工程中,当我们进行UI设计时,可以随意的将一个控件剪切/张贴到另外一个地方。操作方便的背后是什么在发挥作用呢。控件明明是一个复杂的对象,却可以进行剪切张贴。这其中就涉及到了对象的转换。将控件这个复杂的对象转换为字节流,进行复制,然后再将字节流反转为控件对象。这样就实现了控件的随意剪切与张贴。

上述就体现了序列化的应用场合,数据传送。

定义:

序列化:将对象转换为字节流。

反序列化:将字节流转换为对象。

二.使用序列化

格式化器BinaryFormmatter(System.Runtime.Serialization.Formatters.Binary命名空间)

1. 序列化

BinaryFormatter.Serialize(Stream,object) 将需要转换的类型传入(object),以及Stream引用 。然后就会得到stream对象

2.反序列化

BinaryFormatter.DeSerialize(Stream stream)传入stream引用,返回对象。

简单的demo:

三.设计类可序列化,控制类的成员可序列化

1.类可序列化:

类默认是不可序列化的,但是我们在设计一个类时通常需要将其设计为可序列化,方便后续使用。使类可序列化的方法很简单,引入Attribute。在类前面加上[Serializable](是System命名空间,而不是System.Runtime.Serialization命名空间)。这样类就可序列化了。因为设置类可序列化后,默认类中的所有字段都是可序列化的。而不论其是private,protected。这样对于一些需要保护的字段就极其不利了。所以接下来就是控制类的成员可序列化。

2.控制类的成员可序列化

类型中有些字段是不希望其序列化

  • 反序列化后没有意义。比如Windows内核(文件,进程,线程等)这些与进程有关,反序列化后不是同一进程,得到的信息没有意义。而序列化的目的是在于将对象转化为字节流,最终还是需要进行反序列化得到原有结果的。
  • 字段可以通过简单计算得到。这样的字段没必要进行序列化。序列化反而会增加传送的数据量。

那么如何控制字段不可序列化呢

  1. 字段前加上[NonSerialized]即可。但是问题来了,这样我们反序列化就得不到这个字段的原有值了。像上面所述的【能够通过简单计算】得到的字段我们不希望他序列化,但设置了[NonSerialized],这样反序列后得不到想要的值。这样显然也不是我们希望看到的。解决办法就是使用[OnDeserialized]特性
  2. OnDeseriablized(StreamContext context)方法中重新计算标记为未序列化字段,因为有OnDeserialized特性,这样序列格式化器就会识别这个特性,对这个方法进行调用。类似的特性还有OnDeserializing,OnSerializing,OnSerialized。分别在序列化和反序列的不同时期调用。可以根据实际情况来添加对应的方法。看似已经解决了控制类的成员可序列化的问题了。但是又有一个新的问题。如果我现在在类型里添加新的字段。序列化格式化器处于性能的考虑,不会在一开始进行了字段是否可序列化的检查。而是调用时看是否能够序列化。序列化一个对象图时,只要有一个对象不能序列化【注意不是不可序列化】就会报异常。那么如果我们序列化一个类型的实例,在类型中添加新字段,然后反序列化不包含新字段的对象。那肯定会报错
  3. 解决2最后的问题,就可以通过OptionalFieldAttribute特性。这样格式化器就会识别这个特性,不会因为流中不包含这个字段而报错

四. 格式化器如何工作

无论是序列化,还是反序列化,还是识别特性OnSerialized等,都是格式化器在起作用。那么格式化是如何进行序列化与反序列化呢

序列化:

  1. 格式化器调用FormatterServices的GetSerializableMembers()方法,获取到需要序列化的字段
  2. 格式化器根据1取得的序列化字段调用FormatterServices的GetObjectData取得字段的对应值
  3. 格式化将程序集标示和类型名写入流中。
  4. 将1,2,取得的序列化字段和值写入流中。

反序列化:

  1. 读取程序集和类型名称,加载程序集
  2. 为对象分配内存。调用FormatterServices的Get‘UninitzlizedObject()
  3. 初始化字段
  4. 初始化字段对应的值
  5. 将分配的对象,字段,字段对应值引用传递给FormatterServices的PopulateObjectMembers()方法
时间: 2024-12-18 02:53:58

C# 运行时序列化的相关文章

第24章 运行时序列化

什么是序列化和反序列化 序列化(serialization)是将一个对象或者对象图(对象在特定的时间点的一个视图)转换成一个字节流的过程.反序列化(deserialization)是将一个字节流转换回对象图的过程. 应用场景: 应用程序的状态(对象图)可以保存到磁盘文件或数据库中,并在应用程序下次运行时恢复. 一组对象可以轻松复制到Windows 窗体的剪贴板中,再粘贴回同一个或者另一个应用程序. 将对象按值从一个应用程序域中发送到另一个程序域 24.1 序列化/反序列化快速入门 http://

【C#进阶系列】24 运行时序列化

序列化是将对象或者对象图(一堆有包含关系的对象)转换成字节流的过程.而反序列化就是将字节流转为对象或对象图. 主要用于保存.传递数据,使得数据更易于加密和压缩. .NET内建了出色的序列化和反序列化支持. 上一个简单的小例子: using System.Runtime.Serialization.Formatters.Binary; namespace MyTest { class Program { static void Main(string[] args) { MemoryStream

处理Android程序运行时的配置变化

本篇文章翻译自Android官方文档Handling Runtime Changes,有翻译错误请留言告知,多谢. Android程序在运行期间设备的配置是可能发生改变的(例如屏幕的方向,键盘可用性,和语言等).当这些配置发生变化时,Android会重启正在运行的Activity(先调用onDestory(),紧接着调用onCreate()).这个设计是为了让你的程序在配置发生变化时,使用不同的资源自动去适配新的配置机器. 正确的处理重启,一件很重要的事就是通过Activity正常的生命周期去恢

Android处理运行时变更保存数据状态恢复Activity

一.概述 运行时变更就是设备在运行时发生变化(例如屏幕旋转.键盘可用性及语言).发生这些变化,Android会重启Activity,这时就需要保存activity的状态及与activity相关的任务,以便恢复activity的状态. 为此,google提供了三种解决方案: 对于少量数据: 通过onSaveInstanceState(),保存有关应用状态的数据. 然后在 onCreate() 或 onRestoreInstanceState() 期间恢复 Activity 状态. 对于大量数据:用

ASP.NET 5运行时升级到Beta5

(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:在Visual Studio 2015 RTM和Windows 10正式发布之前,微软把开源.NET升级到了beta5,带来了一些增强和改变. 和Visual Studio 2015 RC一起安装的ASP.NET 5运行时是beta4,前几天微软发布了这个运行时的beta5版本.整个升级包括如下几个方面: .NET执行环境(DNX) 支持Nuget v3,恢复包的速度更快 支持全新的.NET目

iOS Objective -C Runtime 运行时之一: 类与对象

// --------------------------------------------------- 参考:南峰子的技术博客 http://southpeak.github.io //---------------------------------------------------- OC语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们编写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等.

Objective-C Runtime 运行时之一:类与对象

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时能够更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等. 这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码.对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行.这个运行时系统即Objc Runtime.Objc Runtime其实是一个Runti

[ObjectC]Runtime 运行时之一:类与对象

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等. 这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码.对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行.这个运行时系统即Objc Runtime.Objc Runtime其实是一个Runtime

Runtime 运行时之一:类与对象

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码时能够更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等. 这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码.对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行.这个运行时系统即Objc Runtime.Objc Runtime其实是一个Runti