技术开发 频道

浅析 .NET 中的 Serialization

  2、实现ISerializable接口

  Serializable属性的功能非常强大,它使得Serialize和Deserialize变得十分简单。但凡事有利必有弊,由Serializable实现的自动序列化方法有时不够灵活。我们并不能完全控制Serialize和Deserialize的行为,而有些时候它们的行为对我们来说很重要。那么我们通过何种方法能够控制Serialize和Deserialize的行为呢?答案就是,自己来实现ISerializable接口。ISerializable接口给予我们更大的自由来控制Serialize和Deserialize,但是无疑我们将不得不写更多的代码。

  下面我们来看看如何实现ISerializabe接口。ISerializable接口位于System.Runtime.Serialization名字空间中,声明如下:

   public inferface ISerializable
   {
   void GetObjectData(SerializationInfo info,
   StreamingContext context);
   } 

  它只有一个方法GetObjectData。因此,像实现其他接口一样,我们必须实现此方法。但与其他接口不同的是,为了Deserialization,我们还必须实现一个特殊的构造函数(我称此构造函数为“序列化构造函数”),此构造函数具有与GetObjectData相同的参数列表。由于此构造函数专门用于.NET Framework在Deserialize时的Reflection机制,因此我们通常将它声明为保护或私有模式。如下:(当然,如果你的class只需要Serialize而不需要Deserialize的话,也可以不实现这个特殊的构造函数)

  

[Serializable] public class Person : ISerializable { public string name = null; public int age = 0; public Person() { } protected Person(SerializationInfo info, StreamingContext context) { name = info.GetString("name"); age = info.GetInt32("age"); } void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("name", name); info.AddValue("age", age); } }

  通过实现ISerializable接口,使得我们有机会在ISerializable.GetObjectData中控制Serialize的行为,在“序列化构造函数”中控制Deserialize的行为。这个接口提供给我们的信息非常全面而灵活,以致于我们甚至可以在这两个方法中耍些花招。比如,我们可以在Deserialize的时候,籍由改变info.FullTypeName来得到一种与被Serialize的对象不同类型的另一个对象等。

  独辟蹊径

  前面谈到过Serialization被运用的典型环境,是对象存储、进程间数据传递等涉及到对象持久性的领域。但实际上,它也能够被运用到其他的许多地方,关键在于我们是否能想到去用运Serialization,有时候思维定式也是很可怕的J。举个例子,我们来看看在Clone方法中如何使用Serialization[1]。

如果我们要为Person类实现Clone方法,我们通常会这样写:

   [Serializable]
   public class Person : ICloneable
   {
   public string name = null;
   public int age = 0;
   public object Clone()
   {
   Person person = new Person();
   person.name = name;
   person.age = age;
   return person;
   }
   }

  如果我们利用Serialization的方法,Clone函数就能写成下面的样子:

   public object Clone()
   {
   MemoryStream stream = new MemoryStream();
   BinaryFormatter formatter = new BinaryFormatter();
   formatter.Serialize(stream, this);
   stream.Position = 0;
   return formatter.Deserialize(stream);
   }

  从这两个实现上看,使用Serialization实现Clone方法似乎并没有什么好处。可是设想如果你面对的是一个复杂的类继承体系,从基类到派生类都需要实现Clone方法。利用第一种实作手法,你将不得不为每一个class写一个Clone方法,而且随着数据成员的增多,这个方法将越来越冗长,并且会由于数据成员的改变而引发错误(我曾经遇到过好几次,由于class中增加了成员变量,而Clone方法没有及时更新,导致运行时错误。呵呵,这种错误还很难调试)。现在你看到用Serialization实现的好处了吧?是的,我们只要在基类中将Clone方法声明为virtual,并用Serialization的方法实现之,然后保证基类和派生类都可以被Serialize,上面所有的麻烦不都迎刃而解了吗?

  总结

  现代软件项目中,无论何种项目都会或多或少地涉及到对象持久性的问题,.NET也不例外,无论是Windows Form、ASP.NET,还是Web Services,都需要处理对象持久性。而Serialization正是.NET为应对这个问题而给出的解法。

0
相关文章