zoukankan      html  css  js  c++  java
  • .Net组件程序设计之序列化

    .Net组件程序设计之序列化

     .Net组件程序设计之序列化

    自动序列化

    Serializable属性

    复制代码
     1     [Serializable]
     2     public class SerializableCase
     3 
     4     {
     5 
     6         public SerializableCase() { }
     7 
     8         private string _State;
     9 
    10         public string State
    11 
    12         {
    13 
    14             get { return _State; }
    15 
    16             set { _State = value; }
    17 
    18         }
    19 
    20     }
    复制代码

    在上面的示例类型上加上Serializable属性这样将示例类型标记为可序列化类型.

    格式化序列化器

     二进制格式器

    复制代码
     1     public class MySerializableCase
     2     {
     3         public static void BinaryFormatterSerialize()
     4         {
     5             IFormatter formatter = new BinaryFormatter();
     6             Stream stream = new FileStream("jin.glory", FileMode.Create, FileAccess.ReadWrite);
     7             using (stream)
     8             {
     9                 SerializableCase serCase = new SerializableCase();
    10                 serCase.State = "Test";
    11                 formatter.Serialize(stream, serCase);
    12             }
    13         }
    14 
    15         public static void BinaryFormatterDesSerialize()
    16         {
    17             Stream stream = new FileStream("jin.glory", FileMode.Open, FileAccess.Read);
    18             IFormatter formatter = new BinaryFormatter();
    19             using (stream)
    20             {
    21                 SerializableCase serCase = formatter.Deserialize(stream) as SerializableCase;
    22                 return serCase.State;
    23             }
    24         }
    25     }
    复制代码

    BinaryFormattSerialize()方法里只是实例化SerializableCase类型,然后对State属性赋值,代表一个状态。调用 MySerializableCase.BinaryFormattSerialize()后.NET把序列化好的文件流保存到了jin.glory文件中.

    图1

    文件的名称和后缀格式都是自己随便定义的。然后再调用反序列化,获取到之前序列化的对象状态。

    1   string state = MySerializableCase.BinaryFormattDesSerialize();
    2   Console.WriteLine(state);

    图2

    SOAP格式器

    SoapFormatter是在命名空间System.Runtime.Serialization.Formatters.Soap下的(在System.Runtime.Serialization.Formatters.Soap.dll中)

    复制代码
     1 public class MySerializableCase
     2     {
     3         public static void SoapFormatterSerialize()
     4         {
     5             IFormatter formatter = new SoapFormatter();
     6             Stream stream = new FileStream("Soap.xml", FileMode.Create, FileAccess.ReadWrite);
     7             using (stream)
     8             {
     9                 SerializableCase serCase = new SerializableCase();
    10                 serCase.State = "Test";
    11                 formatter.Serialize(stream, serCase);
    12             }
    13         }
    14 
    15         public static string SoapFormatterDesSerialize()
    16         {
    17             Stream stream = new FileStream("Soap.xml", FileMode.Open, FileAccess.Read);
    18             IFormatter formatter = new SoapFormatter();
    19             using (stream)
    20             {
    21                 SerializableCase serCase = formatter.Deserialize(stream) as SerializableCase;
    22                 return serCase.State;
    23             }
    24         }
    25     }
    复制代码

     
    和上面的二进制格式化器使用的方式近乎相同,唯一不同的是,使用Soap格式化器生成的序列化文件耗时更长,占用空间也比较大,但是它是遵循着SOAP协议的,这在跨平台操作数据间是很有用的,平台只需要解析重建就能把对象重新的生成出来。

    不可序列化成员

    复制代码
     1     [Serializable]
     2     public class SerializableCase
     3     {
     4         public SerializableCase() { }
     5 
     6         private string _State;
     7 
     8         public string State
     9         {
    10             get { return _State; }
    11             set { _State = value; }
    12         }
    13 
    14         [NonSerialized]
    15         private DonotSerializable _DonotSerializable;
    16 
    17         public DonotSerializable DonotSerializable
    18         {
    19             get { return _DonotSerializable; }
    20             set { _DonotSerializable = value; }
    21         }
    22     }
    23     public class DonotSerializable
    24     {
    25         public DonotSerializable() { }
    26 
    27         public string DonotSerializableData
    28         {
    29             get;
    30             set;
    31         }
    32     }
    复制代码

    修改了一下第一段的示例代码,增加了个属性,并且设置其字段为NonSerialized,这样在.NET序列化这个类的实例的时候,检测到了[NonSerialized]的时候就会跳过它,因为有的对象确实是不适合序列化来进行持久化的,不过这样的做的也会有个问题,就是对象的状态丢失,就是不可序列化的部分会丢失。看一下下面的代码:

    复制代码
     1     public class MySerializableCase
     2     {
     3         public static void BinaryFormatterSerialize()
     4         {
     5             IFormatter formatter = new BinaryFormatter();
     6             Stream stream = new FileStream("jin.glory", FileMode.Create, FileAccess.ReadWrite);
     7             using (stream)
     8             {
     9                 SerializableCase serCase = new SerializableCase();
    10                 serCase.State = "Test";
    11                 serCase.DonotSerializable = new DonotSerializable();
    12                 serCase.DonotSerializable.DonotSerializableData = "DonotSerializableData";
    13                 formatter.Serialize(stream, serCase);
    14             }
    15         }
    16 
    17         public static string BinaryFormatterDesSerialize()
    18         {
    19             Stream stream = new FileStream("jin.glory", FileMode.Open, FileAccess.Read);
    20             IFormatter formatter = new BinaryFormatter();
    21             using (stream)
    22             {
    23                 SerializableCase serCase = formatter.Deserialize(stream) as SerializableCase;
    24                 return serCase.State+"_"+serCase.DonotSerializable.DonotSerializableData;
    25             }
    26         }
    27      }
    复制代码

    修改了上面的二进制格式器的代码,调用一下测试代码我们一起来看下结果:

    1 MySerializableCase.BinaryFormatterSerialize();
    2 string state = MySerializableCase.BinaryFormatterDesSerialize();
    3 Console.WriteLine(state);

    图3

    在反序列化的时候,对象SerializableCase的DonotSerializable属性丢失了,所以才会报错。
    对于这样的情况,.NET提供了IDeserializationCallback接口,它里面只有一个函数void OnDeserialization(object sender),只要实现了IDeserializationCallback,并且在OnDeserialization函数里实现具体的对不可序列化对象的初始化。

    复制代码
     1     [Serializable]
     2     public class SerializableCase:IDeserializationCallback
     3     {
     4         public SerializableCase() { }
     5 
     6         private string _State;
     7 
     8         public string State
     9         {
    10             get { return _State; }
    11             set { _State = value; }
    12         }
    13 
    14         [NonSerialized]
    15         private DonotSerializable _DonotSerializable;
    16 
    17         public DonotSerializable DonotSerializable
    18         {
    19             get { return _DonotSerializable; }
    20             set { _DonotSerializable = value; }
    21         }
    22 
    23         public void OnDeserialization(object sender)
    24         {
    25             _DonotSerializable = new DonotSerializable();
    26             _DonotSerializable.DonotSerializableData = "DonotSerializableData->Test";
    27         }
    28     }
    复制代码

    按照上面的调用方式,来看一下结果:

    图4

    这样是在反序列化的时候,如果检测到了实例类型实现了IDeserializationCallback接口,是在反序列化完成的时候会执行实现了IDeserializationCallback的OnDeserialization()方法,这样可以对一些不可序列化的属性状态在这个方法里来实现。

    序列化事件

    .NET2.0 
    引进了对序列化事件的支持,当序列化和反序列化的时候,.NET在你的类上调用指定的方法,.NET中定义了四个序列化和反序列化事件。
    serializing事件是在序列化发生之前被触发,
    serialized 事件是在序列化之后被触发,
    deserializing事件是在反序列化之前被触发,
    deserialized事件是在反序列化之后被触发。

    引用先前的示例代码SerializableCase类的初始代码:

    复制代码
        [Serializable]
        public class SerializableCase //:IDeserializationCallback
        {
            public SerializableCase() { }
            private string _State;
            public string State
            {
                get { return _State; }
                set { _State = value; }
            }
        }
    复制代码

    添加了事件后的示例代码是这样的:

    复制代码
     1     [Serializable]
     2     public class SerializableCase 
     3     {
     4         public SerializableCase() { }
     5         private string _State;
     6         public string State
     7         {
     8             get { return _State; }
     9             set { _State = value; }
    10         }
    11 
    12         [OnSerializing]
    13         private void OnSerializing(StreamingContext context)
    14         {
    15             _State = "此时的状态是:序列化之前";
    16             Console.WriteLine(State);
    17         }
    18 
    19         [OnSerialized]
    20         private void OnSerialized(StreamingContext context)
    21         {
    22             _State = "此时的状态是:序列化之后";
    23             Console.WriteLine(State);
    24         }
    25 
    26         [OnDeserializing]
    27         private void OnDeserializing(StreamingContext context)
    28         {
    29             _State = "此时的状态是:反序列化之前";
    30             Console.WriteLine(State);
    31         }
    32 
    33         [OnDeserialized]
    34         private void OnDeserialized(StreamingContext context)
    35         {
    36             _State = "此时的状态是:反序列化之后";
    37             Console.WriteLine(State);
    38         }
    39     }
    复制代码

    使用之前定义好的MySerializableCase类型中的静态方法,稍作修改来演示一下,

    复制代码
     1         public static void SoapFormatterSerialize()
     2         {
     3             IFormatter formatter = new SoapFormatter();
     4             Stream stream = new FileStream("Soap.xml", FileMode.Create, FileAccess.ReadWrite);
     5             using (stream)
     6             {
     7                 SerializableCase serCase = new SerializableCase();
     8                 formatter.Serialize(stream, serCase);
     9             }
    10         }
    11         public static string SoapFormatterDesSerialize()
    12         {
    13             Stream stream = new FileStream("Soap.xml", FileMode.Open, FileAccess.Read);
    14             IFormatter formatter = new SoapFormatter();
    15             using (stream)
    16             {
    17                 SerializableCase serCase = formatter.Deserialize(stream) as SerializableCase;
    18                 return serCase.State;
    19             }
    20             
    21         }
    复制代码

    测试代码:

    1 MySerializableCase.SoapFormatterSerialize();
    2 MySerializableCase.SoapFormatterDesSerialize();
    3 Console.ReadLine();

    图5

    从结果中就很明显的显示出来了,这里要说几句题外话,细心的朋友可能发现了,在SerializableCase类型中的四个事件函数签名都是相同的,这是因为在.NET中为这个这个序列化和反序列化事件定义的委托就是这个签名,在这个类型实例序列化和反序列化的时候会检测到.NET会反射实例内部所有的函数 检测是否有附加了序列化事件,如果判断了有则会继续检查这个函数的签名,如果函数签名也匹配了,就会把这个函数挂上委托。

    可以这样指定一个函数为事件指定调用函数:

    复制代码
    1 [OnSerializing]
    2 [OnSerialized]
    3 [OnDeserializing]
    4 [OnDeserialized]
    5 private void OnGenericSerializEventMethod(StreamingContext context)
    6 {
    7     ……
    8 }
    复制代码

    本篇幅序列化内容结束。

    作者:金源

    出处:http://www.cnblogs.com/jin-yuan/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

     
     
    标签: C#WinForm.NET
  • 相关阅读:
    【BZOJ5137】Standing Out from the Herd(后缀自动机)
    【BZOJ1564】【NOI2009】二叉查找树(动态规划)
    仙人掌&圆方树学习笔记
    【CF487E】Tourists(圆方树)
    【BZOJ2125】最短路(仙人掌,圆方树)
    【BZOJ4818】序列计数(动态规划,生成函数)
    【BZOJ1023】仙人掌图(仙人掌,动态规划)
    【BZOJ4316】小C的独立集(仙人掌,动态规划)
    【BZOJ4316】小C的独立集(动态规划)
    【BZOJ3240】【NOI2013】矩阵游戏(数论)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3746775.html
Copyright © 2011-2022 走看看