千家信息网

如何理解.Net组件程序设计中的序列化

发表于:2025-01-18 作者:千家信息网编辑
千家信息网最后更新 2025年01月18日,如何理解.Net组件程序设计中的序列化,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。.Net组件程序设计之序列化自动序列化Seriali
千家信息网最后更新 2025年01月18日如何理解.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 State11 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 DonotSerializable18         {19             get { return _DonotSerializable; }20             set { _DonotSerializable = value; }21         }22     }23     public class DonotSerializable24     {25         public DonotSerializable() { }26 27         public string DonotSerializableData28         {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 DonotSerializable18         {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 }

看完上述内容,你们掌握如何理解.Net组件程序设计中的序列化的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

0