当前位置: 首页 > news >正文

《CLR via C#》 之运行时序列化(3)

序列化成不同类型

    [Serializable]
    public sealed class Singleton : ISerializable
    {
        private static readonly Singleton s_theOneObject = new Singleton();

        public string Name = "Oliver";
        public DateTime Date = DateTime.Now;

        private Singleton()
        {
        }

        public static Singleton GetSingleton()
        {
            return s_theOneObject;
        }

        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.SetType(typeof(SingletonSerializationHelper));
        }
    }

    [Serializable]
    public sealed class SingletonSerializationHelper : IObjectReference
    {
        public object GetRealObject(StreamingContext context)
        {
            return Singleton.GetSingleton();
        }
    }

单例在每个AppDomain只能存在它自己一个实例。上面的例子是,如何序列化/反序列化一个单例。

我们来测试一下上面的代码

       static void Main(string[] args)
        {
            Singleton[] a1 = { Singleton.GetSingleton(), Singleton.GetSingleton() };
            Console.WriteLine(a1[0] == a1[1]); // check reference is the same.
            using (var stream = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();

                formatter.Serialize(stream, a1);
                stream.Position = 0;
                Singleton[] a2 = (Singleton[])formatter.Deserialize(stream);

                Console.WriteLine(a2[0] == a2[1]);
                Console.WriteLine(a1[0] == a2[0]);
            }
        }

输出是全是“True”。这说明我们序列化,反序列化出来的对象的实例都是同一个。

现在我们分析一下测试代码来理解一下里面到底发生了什么。

  1. 首先定义了一个Singleton的数组。在初始化数组时,Singleton里面静态字段先被初始化。Singleton将一个实例存放在私有静态字段m_theOneObject里。然后,静态方法GetSingleton将引用返回,赋值给数组内元素。
  2. 因为是两个元素的引用相同,故说明两个元素是同一个实例。
  3. 接下来说明一下using代码段中,序列化与反序列化的过程。序列化第一个数组元素时,格式化器检测到Singleton类型继承自ISerializable接口,并调用了GetObjectData方法。在这个方法中,调用SerializationInfo的SetType方法,向它传递SingletonSerializationHelper类型。GetObjectData方法中只调用了SetType,并没有添加更多信息。同时格式化器自动检测出连个数组元素都引用一个对象,所以格式化器只序列化一个对象。
  4. 反序列化时,格式化器尝试反序列化一个SingletonSerializationHelper对象,这是格式化器之前被“欺骗”所序列化的东西。(因为这里反序列化一个SingletonSerializationHelper类型的对象,所以并没有为Singleton添加特殊构造函数。)格式化器构造好SingletonSerializationHelper对象后,发现这个类型实现了System.Runtime.Serialization.IObjectReference接口。如果类型实现了这个接口,格式化器会调用GetRealObject方法。这个方法返回在对象反序列化好之后真正想要引用的对象。
  5. GetRealObject方法返回Singleton的实例。所以最后都将返回true。

这种可以将对象序列化成另外一个类的行为,主要是出于两个方面:

  • 允许开发人员序列化最初没有设计成要序列化的一个类型
  • 允许开发人员提供一个种方式将类型的一个版本映射到类型的另一个不同的版本

序列化代理

序列化代理就是为了实现序列化成其他类型的一种工作机制。

序列化代理必须实现System.Runtime.Serialization.ISerializationSurrogate接口。

例子:本地的DateTime值,如果你想要在世界其他地方想要用你的DateTime,你如何保证在世界各地看到的时间都是对的呢?

    internal sealed class UniversalToLocalTimeSerializationSurrogate : ISerializationSurrogate
    {

        public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Date", ((DateTime)obj).ToUniversalTime().ToString("u"));
        }

        public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
        {
            return DateTime.ParseExact(info.GetString("Date"), "u", null).ToLocalTime();
        }
    }

GetObjectData方法在这里的工作方式与ISerializable接口的GetObjectData方法差不多。唯一的区别在于,ISerializationSurrogate的GetObjectData方法要获取一个额外的参数,要对序列化的”真实“对象的一个引用。

        private static void SerializationSurrogateDemo()
        {
            using (var stream = new MemoryStream())
            {
// 1. Formatter IFormatter formatter
= new SoapFormatter(); // 2. Selector SurrogateSelector ss = new SurrogateSelector(); // 3. add DateTime to surrogate ss.AddSurrogate(typeof(DateTime), formatter.Context, new UniversalToLocalTimeSerializationSurrogate());
// AddSurrogate can be added multi times // 4. set selector to surrogate formatter.SurrogateSelector
= ss; DateTime localTimeBeforeSerialize = DateTime.Now; formatter.Serialize(stream, localTimeBeforeSerialize); stream.Position = 0; Console.WriteLine(new StreamReader(stream).ReadToEnd()); stream.Position = 0; DateTime localTimeAfterDeserialize = (DateTime)formatter.Deserialize(stream); } }

1-4执行完毕后,格式化器就准备好使用已登记的代理类型。

 

转载于:https://www.cnblogs.com/OliverZh/archive/2013/06/08/CLRViaCSharp3.html

相关文章:

  • 一些可能没用过的调试窗口
  • Uboot 运行时内存的分配 -- 转
  • Linux系统下4个扇区的解释
  • Kerberos简介
  • ArgoUML 的简单用法
  • 修改eclipse自动生成的comments中的author名字
  • 怎么配置zen coding,我用的是Adobe Dreamweaver CS5 这个有解决么?
  • 安装jdk、安装Tomcat
  • MongoDB学习笔记
  • 中小企业如何设计存储系统方案
  • 九位不同数字乘法等式的递归与非递归回溯算法(三)
  • 超棒的JS移动设备滑动内容幻灯实现 - Swiper
  • 关于SQLite,SQLCipher和FMDB
  • Android自定义组合控件
  • js判断客户浏览器类型,版本
  • [译]Python中的类属性与实例属性的区别
  • 【node学习】协程
  • HTTP中的ETag在移动客户端的应用
  • Selenium实战教程系列(二)---元素定位
  • Vim 折腾记
  • 分布式熔断降级平台aegis
  • 高度不固定时垂直居中
  • 简单数学运算程序(不定期更新)
  • 系统认识JavaScript正则表达式
  • Spring Batch JSON 支持
  • ​Java并发新构件之Exchanger
  • ​力扣解法汇总946-验证栈序列
  • #162 (Div. 2)
  • #include
  • (175)FPGA门控时钟技术
  • (C语言)二分查找 超详细
  • (C语言)共用体union的用法举例
  • (ZT)一个美国文科博士的YardLife
  • (第8天)保姆级 PL/SQL Developer 安装与配置
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET 中 GetProcess 相关方法的性能
  • .NET 中创建支持集合初始化器的类型
  • .NET文档生成工具ADB使用图文教程
  • [20140403]查询是否产生日志
  • [ABC294Ex] K-Coloring
  • [AutoSar]BSW_Com02 PDU详解
  • [BZOJ 3680]吊打XXX(模拟退火)
  • [C#]winform制作仪表盘好用的表盘控件和使用方法
  • [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
  • [CUDA 学习笔记] CUDA kernel 的 grid_size 和 block_size 选择
  • [dfs] 图案计数
  • [G-CS-MR.PS02] 機巧之形2: Ruler Circle
  • [iOS]-NSTimer与循环引用的理解
  • [LeetCode]—Add Binary 两个字符串二进制相加