利用对象序列化深表克隆对象

来源:互联网 发布:localhost修改php 编辑:程序博客网 时间:2024/06/07 10:11

在.NET上,一切都是对象。这种安排的后果之一就是在当将一个变量赋值给另一个变量的时候,会得到两个指向同一对象的变量,而不是两个不同的数据副本(除非是使用值类型而不是引用类型)。一般情况下,可以通过调用类所公开的一个特殊方法得到一个数据的副本。在.NET世界中,类应当实现ICloneable接口并公开这个接口的惟一方法Clone,让外部调用知道它能够创建类的实例的副本。框架中有多个对象可以实现这个接口,包括Array、ArrayList、BitArray、Font、Icon、Queue和Stack。

        大多数的时候,实现ICloneable接口都相当的简单。所有其他类都是从System.Object 类继承来的。该类所定义的MemberwiseClone方法可以帮助复制对象,而无需手动复制对象的各个属性:

       // Implements ICloneable.Clone 方法。

       public object Clone() 

       {

           // 对象属性如果是复杂类型,那么创建的仍然是其浅表副本。

           // 对象属性如果是复杂类型,那么复制仍然需要手动。

           // 只是利用MemberwiseClone复制所有的非对象值。

            return this.MemberwiseClone();

       }

        但是,这种方法使我们使用时感到不爽,因为,只有通过更改对象定义的源代码才可以克隆一个对象,因为MemberwiseClone方法是受保护的,它只有在类的内部才可以被访问。还有,也是在多数情况下更为重要的一个方面,MemberwiseClone方法执行的是对象的浅表复制——也就是说,它创建了对象的一个副本,但是没有创建该对象所引用的其他任何对象的副本。(就是说,对象内部的数据成员如果是引用的话,还是得我们手动复制的,如果对象图非常复杂,那么我们所面对的工作是多么的繁杂,嗷嗷不爽。)

       使用对象序列化来处理复杂的对象图可以同时解决前面所提到的两个问题。实际上,可以创建一个通用的方法来对任何对象进行深表克隆。

        这是一个简单的提供序列化克隆对象方法:

        public static object CloneObject(object obj)
        {

              // 创建内存流
              using(System.IO.MemoryStream ms = new MemoryStream(1000))
              {
                     object CloneObject;

                     // 创建序列化器(有的书称为串行器)

                     // 创建一个新的序列化器对象总是比较慢。
                     BinaryFormatter bf = new BinaryFormatter(null,
 new StreamingContext(StreamingContextStates.Clone));
                     // 将对象序列化至流

                     bf.Serialize(ms, obj);

                     // 将流指针指向第一个字符

                     ms.Seek(0, SeekOrigin.Begin);
                   

                     // 反序列化至另一个对象(即创建了一个原对象的深表副本)

                    CloneObject = bf.Deserialize(ms);

                     // 关闭流 
                     ms.Close();
                     return CloneObject;
              }
       }

以下,是一个使用这个方法克隆的例子:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;

namespace ObjectCloneBySerialize
{

 class Class1
 {

  [STAThread]
  static void Main(string[] args)
  {
   ArrayList Persons = new ArrayList();
   Person Fangxing = new Person("Fang Xing", "Male");
   Persons.Add(Fangxing);
   Person Liwei = new Person("Li Wei", "Male");
   Persons.Add(Liwei);

   ArrayList ClonedPersons = (ArrayList)CloneObject(Persons);
   Person Zhangsan = new Person("Zhang San", "Male");
   ClonedPersons.Add(Zhangsan);

   Console.WriteLine("===== Before Clone =====");
   for(int i=0; i<Persons.Count; i++)
   {
    Person someone = (Person)Persons[i];
    Console.WriteLine(someone.Name + " " + someone.Gender);
   }
   
   Console.WriteLine("===== After Clone =====");
   for(int i=0; i<ClonedPersons.Count; i++)
   {
    Person someone = (Person)ClonedPersons[i];
    Console.WriteLine(someone.Name + " " + someone.Gender);
   }

   Console.ReadLine();

  }

  public static object CloneObject(object obj)
  {
   using(System.IO.MemoryStream ms = new MemoryStream(1000))
   {
    object CloneObject;
    BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
    bf.Serialize(ms, obj);
    ms.Seek(0, SeekOrigin.Begin);
    CloneObject = bf.Deserialize(ms);
    ms.Close();
    return CloneObject;
   }
  }
 }

 [Serializable]
 class Person
 {
  private string m_Name;
  private string m_Gender;

  public string Name
  {
   get{return m_Name;} 
  }

  public string Gender
  {
   get{return m_Gender;} 
  }

  public Person(string name, string gender)
  {
   m_Name = name;
   m_Gender = gender;
  }
 
 }
}

 

       

// 复制对象

 

private object Clone(object objSource)
{
            System.Xml.Serialization.XmlSerializer xmls = new System.Xml.Serialization.XmlSerializer(objSource.GetType());
            System.IO.MemoryStream menStr = new System.IO.MemoryStream();
            xmls.Serialize(menStr, objSource);
            menStr.Position = 0;
            return xmls.Deserialize(menStr);
 }

原创粉丝点击