zoukankan      html  css  js  c++  java
  • 第一节:序列化和反序列化快速入门

      static void Main(string[] args)
            {
    
                var objectGraph = new List<string> { "Jeff", "Kristin", "Aidan", "Grant" };
    
                Stream stream = SerializerToMemory(objectGraph);
                //为了演示,将一切都重置
                stream.Position = 0;
                objectGraph = null;
    
                objectGraph = (List<string>)DeserializerFromMemory(stream);
                foreach (var s in objectGraph)
                {
                    Console.WriteLine(s);
                }
    }

    private static MemoryStream SerializerToMemory(Object objectGraph)
    {

    
    

    //构造一个流来容纳序列化的对象
    MemoryStream stream = new MemoryStream();
    //构造一个序列化格式器,它负责所有的辛苦工作
    BinaryFormatter formatter = new BinaryFormatter();
    //告诉格式化器将对象序列化到流中
    formatter.Serialize(stream, objectGraph);

    
    

    return stream;
    }
    private static Object DeserializerFromMemory(Stream stream)
    {
    //构造一个序列化格式器来做所有辛苦工作
    BinaryFormatter formatter = new BinaryFormatter();
    return formatter.Deserialize(stream);
    }

     

    看起来一切都简单!SerializerToMemory方法构造一个MemoryStream对象。这个对象标明要将序列化好的对象放到哪里。然后,方法构造一个BinaryFormatter对象。格式化器是实现了System.Runtime.Serialization.IFormatter接口的一个类型,它知道如何序列化和反序列化一个对象图。FCL提供了两个格式化器:BinaryFormatter和System.Runtime.Serialization.Formatters.Soap.SoapFormatter(System.Runtime.Serialization.Formatters.Soap.dll程序集中实现的)。

    注意  从.NET Framework3.5起,SoapFormatter类已被废弃,应避免在生产过程中使用。然而,对序列化代码进行调试时,它仍然有一定的用途,因为它能生成便于阅读的XML文本。要在生产过程中产用XML序列化和反序列化,请参见XmlSerializer 和DataContractSerializer类

    要序列化一个对象图,只需要调用格式化器的Serialize方法,并向它传递两样东西:对一个流对象的引用,以及要序列化对象图的一个引用。流对象标识了序列化好的字节应放到哪里,它可以使从System.IO.Stream抽象类派生的任何一个对象。也就是说,可将对象图序列化成一个MemoryStream、FileStream或者NetworkStream等等。

    Serialize的第二个参数是一个对象引用。这个对象可以使任何东西,可以使一个Int32,String,DateTime,Exception,List<String>或者Dictionary<Int32,DateTime>等等。

    objectGraph参数引用的对象可饮用其他对象。例如,objectGraph可引用一个集合,而这个集合引用一个数组。这些对象还可以继承引用其他对象。当格式化器的Serialize方法被调用时,对象图中的所有对象都被序列化到流中。

    格式化器参数对每个对象的类型进行描述的元数据,从而了解如何序列化完整的对象图。序列化时,Serialize方法利用反射来查看每个对象的类型中都有哪些实例字段。在这些字段中,任何一个引用了其他对象,格式化器的Serialize方法就知道哪些对象也要序列化。

    格式化器的算法非常智能。它们知道如何确保对象图中的每个对象都只序列化一次。换言之,如果对象图的两个对象相互引用,格式化器就会检测到这一点,每个对象都只序列化一次,避免进入无限循环。

    在上诉代码的SerializerToMemory方法中,当格式化器的Serialize方法返回后,MemoryStream直接返回给调用者。应用程序可以按照自己希望的任何方式利用这个字节数组的内容。例如,可以把他保存到一个文件中,复制到剪切板中或者通过网络发送等。

    DeserializerFromMemory方法将一个流反序列化成一个对象图。该方法比用于序列化对象图的方法更简单。在代码中,我构造了一个BinaryFormatter,然后调用它的Deserialize方法。这个方法获取流作为参数,返回对反序列化好的对象图中的根对象的一个引用。

    注意:下面是一个有趣而使用的方法,它利用序列化创建对象的一个拷贝(或者说一个克隆体):

      private static Object DeepClone(Object original)
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Context = new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone);
                    //将对象图序列化到内存流中
                    formatter.Serialize(stream,original);
                    //反序列化前,定为到内存流的起始位置
                    stream.Position = 0;
                    //将对象图反序列化成一组新对象,并且向调用者返回对象图的根(深拷贝)
                    return formatter.Deserialize(stream);
                }
            }

    在内部,格式化器的Deserialize方法会检查流的内容,构造流中所有对象的实例,并初始化这些对象的所有字段,使他们具有和当初序列化时相同的值,通常将Deserialize方法返回的对象引用转型为应用程序期待的类型。

    在这个时候,我觉得有必要补充几点注意事项。首先,是由你来保证代码为序列化和反序列化使用相同的格式化器。例如,不要写代码用SoapFormatter序列化一个对象,再用BinaryFormatter反序列化。如果Deserialize发现自己解释不了一个流的内容,就会抛出一个System.Runtime.Serialization.SerializationException异常。

    其次,可将多个对象图序列化到一个流中,这是很有用的一个操作。例如,假如有以下两个类定义:

      [Serializable]    sealed class Customer { }
      [Serializable]    sealed class Order { }

    然后,在应用程序的主要类中,定义了以下静态字段:

    private static List<Customer> s_customers = new List<Customer>();
            private static List<Order> s_pendingOrders = new List<Order>();
            private static List<Order> s_processedOrders = new List<Order>();

    现在,可以利用如下所示的一个方法,将应用程序的状态序列化到单个流中:

     private static void SaveApplicationState(Stream stream)
            {
                BinaryFormatter binary = new BinaryFormatter();
                //序列化我们的应用程序的完整状态
                binary.Serialize(stream, s_customers);
                binary.Serialize(stream, s_pendingOrders);
                binary.Serialize(stream, s_processedOrders);
            }
    

      

    为了重新构建应用程序状态,可以使用如下所示的一个方法发序列化状态:

    private static void RestoreApplicationState(Stream stream)
            {
                BinaryFormatter binary = new BinaryFormatter();
                //反序列化我们应用程序的完整状态(和序列化的顺序一样)
                s_customers = (List<Customer>)binary.Deserialize(stream);
                s_pendingOrders = (List<Order>)binary.Deserialize(stream);
                s_processedOrders = (List<Order>)binary.Deserialize(stream);
            }

    第三也是最后一点注意事项与程序集有关。序列化一个对象时,类型的全名和类型的定义程序集的名称会被写入流。默认情况下,BinaryFormatter会输出程序集的完整标识符,其中包含程序集的文件名(无扩展名),版本号,语言文化以及公钥信息。反序列化一个对象向时,格式化器首先获取程序集标识信息,并通过调用Assembly的Load方法,确保程序集以加载到正在执行的AppDomain。

    程序集加载之后,格式化器在程序集中查找与要反序列化的对象匹配的一个类型。如果程序集不包含一个匹配的类型,就抛出一个异常,不再对更多的对象序列化。如果找到一个匹配的类型,就创建类型的一个实例,并用流中包含的值对其字段进行初始化。如果类型中的字段与流中读取的字段名不完全匹配,就抛出一个异常,不再对更多的对象进行序列化。

  • 相关阅读:
    5. Mybatis UPDATE更新,DELETE删除
    3. Mybatis Insert
    4. selectKey语句属性配置细节
    2. Mybatis Select
    uoj#282. 长度测量鸡(构造)
    uoj#276. 【清华集训2016】汽水(分数规划+点分治)
    uoj#275. 【清华集训2016】组合数问题(数位dp)
    uoj#274. 【清华集训2016】温暖会指引我们前行(LCT)
    uoj#273. 【清华集训2016】你的生命已如风中残烛(组合数学)
    uoj#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强(矩阵+三维FWT)
  • 原文地址:https://www.cnblogs.com/bingbinggui/p/4620948.html
Copyright © 2011-2022 走看看