• 第七节:将类型序列化为不同的类型以及将类型反序列化为不同的对象


    .NET Framework的序列化架构相当全面,本节要讨论如何设计一个类型,本节要讨论如何设计一个类型,它能将自己的序列化或反序列化成一个不同的类型或对象。下面列举一些有趣的例子。

    1、         有的类型(比如System.DBNull和System.Reflection.Missing)设计成每个AppDomain一个实例。我们经常把这些类型称为单实例类型。给定一个DBNull对象引用,序列化和反序列化它不应造成在AppDomain中创建一个DBNull对象。序列化后,返回的引用应指向AppDomain中现有的DBNull对象。

    2、         对于某些类型来说(比如System.Type,System.Reflection.Assembly和其他反射类型,比如MemberInfo),每个类型、每个程序集或每个成员等只有一个实例。例如,假定一个数组中的每个元素都引用一个MemberInfo对象,其中有5个元素都引用一个MemberInfo对象。在序列化和反序列化这个数组之后,当初引用一个MemberInfo对象的5个元素现在还是应该引用一个MemberInfo对象。除此之外,这些元素引用的那个MemberInfo对象还必须实际对应于AppDomain中的一个特定的成员。在轮询数据库连接对象或者其他任何类型的对象时,也可以利用这个单实例功能。

    3、         对于远程控制的对象,CLR序列化与服务器对象有关的信息。在客户端上反序列化时,会造成CLR创建一个代理对象。这个代理对象的类型有别于服务器对象的类型,但这对于客户端代码来说是透明的。客户端直接在代理对象上调用实例方法。然后,代理代码内部会将调用远程发送给服务器,有后者实际执行请求的操作。

    下面来看看一些示例代码,他们展示了如何正确序列化和反序列化一个单实例类型:

    [Serializable]
        public sealed class Singleton : ISerializable
        {
            private static readonly Singleton s_theOneObject = new Singleton();
            public string Name = "Jeff";
            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(SingleSerializationHelper));
            }
            [Serializable]
            private sealed class SingleSerializationHelper : IObjectReference
            {
                //这个方法在对象反序列化之后调用
                public Object GetRealObject(StreamingContext context)
                {
                    return Singleton.GetSingleton();
                }
            }
        }

    Singleton类所代表的类型规定每个AppDomain只能存在它自己的一个实例。以下代码测试Singleton的序列化和反序列化代码,保证AppDomain中存在Singleton类型的一个实例:

      private static void SingletonSerializationTest()
            {
                Singleton[] a1 = { Singleton.GetSingleton(), Singleton.GetSingleton() };
                Console.WriteLine("do both elements refer to the same object ?" + (a1[0] == a1[1]));//true
    
                using (var stream = new MemoryStream())
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, a1);
                    stream.Position = 0;
                    Singleton[] a2 = (Singleton[])formatter.Deserialize(stream);
    
                    Console.WriteLine("do both elements refer to the same object ?" + (a2[0] == a2[1]));//true
                    Console.WriteLine("do both elements refer to the same object ?" + (a2[0] == a2[0]));//true
                }
            }

    现在,我们通过分析代码来理解所发生的事情。Singleton类型加载到AppDomain中时,CLR调用它的静态构造器,它构造一个对象,并将对象的引用保存到静态字段s_theOneObject中。Singleton类没有提供任何公共构造器,这防止了其他任何代码构造类的其他实例。

    在SingletonSerializationTest中,我们创建了包含两个元素的一个数组;每个元素都引用Singleton对象。为了初始化两个元素,我们调用Singleton的静态GetSingleton方法。这个方法返回对一个Singleton对象的引用。对Console的WriteLine方法的第一个调用显示true,证明两个元素引用的是同一个对象。

    现在SingletonSerializationTest调用格式化器的Serialize方法序列化数组及其元素。序列化第一个Singleton时,格式化器检测Singleton类型实现了ISerializable接口,并调用GetObjectData方法。这个方法调用SetType,向它传递SingleSerializationHelper类型,告诉格式化器将Singleton对象序列化成一个SingleSerializationHelper对象。由于AddValue没有调用,所以没有额外的字段信息写入流。由于格式化器自动检测出两个数组元素都引用一个对象,所以格式化器只能序列化一个对象。

    序列化数组之后,SingletonSerializationTest调用格式化器的Deserialize方法。对流进行反序列化时,格式化器尝试反序列化一个SingleSerializationHelper对象,这是格式化器之前被“欺骗”所序列化的东西。构造好SingleSerializationHelper对象够,格式化器发现这个类型实现了IObjectReference接口,格式化器会调用GetRealObject方法。这个方法返回在对象反序列化好之后你整整想要引用的对象。在我的例子中,SingleSerializationHelper类型让GetRealObject返回对AppDomain中已存在的Singleton中已存在的Singleton对象的一个引用。所以,当格式化器的Deserialize方法返回时,a2数组包含两个元素,两者都引用Appdomin的Singleton对象。

  • 相关阅读:
    redis主从复制
    基于代价解析的最优路径规划CBO
    数组对象判断对象中值是否为空,为空删除当前对象
    Nginx 常用配置,避坑指南!
    windows下用nginx配置https服务器
    [转]Powershell中替换文件内容的方法
    wget 和 curl命令
    数据仓库和数据湖的区别
    真实项目中Switch语句的高级写法
    String.length()和String.getBytes().length的用法讲解
  • 原文地址:https://www.cnblogs.com/bingbinggui/p/4621872.html
Copyright © 2020-2023  润新知