Superficial and deep copy copy in C #

    Get a new copy of the superficial example, one identical to the original type, the value of the type field of the same copy. However, if the field is a reference type, then the copy is the reference, rather than the object. If you want the object reference fields also copy the past, it is called a deep copy.

1.System.Object provides a method MemberwiseClone protected, can be used to achieve the "shallow" copy. Since the method is marked as "protected" level, therefore, we can only access the method in the derived class or the class inside:

        //浅复制
        public Student ShallowClone()
        {
            return this.MemberwiseClone() as Student;
        }

2. Conditions serialization and deserialization manner, although this embodiment can achieve a deep copy, but outside the reference MemoryStream stream must remember to close the created class :( serializable: 1 Public, 2 increasing the Serializable class attribute flag)

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

//深拷贝  
        public Student DeepClone()
        {
            using (Stream objectStream = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, this);
                objectStream.Seek(0, SeekOrigin.Begin);
                return formatter.Deserialize(objectStream) as Student;
            }
      

3. In a foreigner writing a blog (http://www.codeproject.com/Articles/3441/Base-class-for-cloning-an-object-in-C), using the reflection method to solve this problem. He wrote a BaseObject class, if we extend this class can be achieved depth copy, the following is his realization:

Create an implementation ICloneableinterface abstract class default behavior of the so-called default behavior is to use the following class library function to copy each field.

1. traversal class of each field to see if support ICloneableinterface.

2. If you do not support ICloneablethe interface, according to the following rule set, i.e. if the field is a value type, then copy it, if the reference type is copied on an object field points.

3. If supported ICloneable, the use of cloning methods in which a subject is set Cologne.

4. If the field supports the IEnumerable interface, you need to see if it supports or IDirectionary IList interfaces, if supported, to see whether to support an iterative set of ICloneable interface.

We have to do is make all of the fields support ICloneable interface.

BaseObject implementation:


///
<summary> /// BaseObject class is an abstract class for you to derive from. /// Every class that will be dirived from this class will support the /// Clone method automaticly.<br> /// The class implements the interface ICloneable and there /// for every object that will be derived <br> /// from this object will support the ICloneable interface as well. /// </summary> using System.Reflection;
using System.Collections;
public abstract class BaseObject : ICloneable { /// <summary> /// Clone the object, and returning a reference to a cloned object. /// </summary> /// <returns>Reference to the new cloned /// object.</returns> public object Clone() { //First we create an instance of this specific type. object newObject = Activator.CreateInstance( this.GetType() ); //We get the array of fields for the new type instance. FieldInfo[] fields = newObject.GetType().GetFields(); int i = 0; foreach( FieldInfo fi in this.GetType().GetFields() ) { //We query if the fiels support the ICloneable interface. Type ICloneType = fi.FieldType. GetInterface( "ICloneable" , true ); if( ICloneType != null ) { //Getting the ICloneable interface from the object. ICloneable IClone = (ICloneable)fi.GetValue(this); //We use the clone method to set the new value to the field. fields[i].SetValue( newObject , IClone.Clone() ); } else { // If the field doesn't support the ICloneable // interface then just set it. fields[i].SetValue( newObject , fi.GetValue(this) ); } //Now we check if the object support the //IEnumerable interface, so if it does //we need to enumerate all its items and check if //they support the ICloneable interface. Type IEnumerableType = fi.FieldType.GetInterface ( "IEnumerable" , true ); if( IEnumerableType != null ) { //Get the IEnumerable interface from the field. IEnumerable IEnum = (IEnumerable)fi.GetValue(this); //This version support the IList and the //IDictionary interfaces to iterate on collections. Type IListType = fields[i].FieldType.GetInterface ( "IList" , true ); Type IDicType = fields[i].FieldType.GetInterface ( "IDictionary" , true ); int j = 0; if( IListType != null ) { //Getting the IList interface. IList list = (IList)fields[i].GetValue(newObject); foreach( object obj in IEnum ) { //Checking to see if the current item //support the ICloneable interface. ICloneType = obj.GetType(). GetInterface( "ICloneable" , true ); if( ICloneType != null ) { //If it does support the ICloneable interface, //we use it to set the clone of //the object in the list. ICloneable clone = (ICloneable)obj; list[j] = clone.Clone(); } //NOTE: If the item in the list is not //support the ICloneable interface then in the //cloned list this item will be the same //item as in the original list //(as long as this type is a reference type). j++; } } else if( IDicType != null ) { //Getting the dictionary interface. IDictionary dic = (IDictionary)fields[i]. GetValue(newObject); j = 0; foreach( DictionaryEntry de in IEnum ) { //Checking to see if the item //support the ICloneable interface. ICloneType = de.Value.GetType(). GetInterface( "ICloneable" , true ); if( ICloneType != null ) { ICloneable clone = (ICloneable)de.Value; dic[de.Key] = clone.Clone(); } j++; } } } i++; } return newObject; } }

 Wrote example, the first test under the above three ways, I found that if a class contains a member variable of type Array, can be replicated depth. However, if the member variable containing the List, List members or shallow copy (and will be reported in the original data is modified). The reason is that Array inherited ICloneable, but List did not inherit, will implement the method BaseObject in the List as a member variable of a value type variable direct assignment. My solution is to create MyList class, implement the Clone method:

    [The Serializable] 
     public  class of MyList <T>: List <T> , the ICloneable 
    { 
        // clone a new List 
        public  Object Clone () 
        { 
            of MyList <T> = newList new new of MyList <T> ();
             the foreach (T Item in  the this ) {       // which are created by each member object 
                newList.Add (the Activator.CreateInstance <T> ()); 
            } 
            return newList; 
        } 
    } 
    [the Serializable] 
    public  class Student: BaseObject 
    {
        public int Age;
        public string Name;
        public MyList<Pet> PetList;

        //浅复制
        public Student ShallowClone()
        {
            return this.MemberwiseClone() as Student;
        }

        //深拷贝  
        public Student DeepClone()
        {
            using (Stream objectStream = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, this);   //序列
                objectStream.Seek(0, SeekOrigin.Begin);
                return formatter.Deserialize(objectStream) as Student;//反序列
            }
        }

        public string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("Age:{0}, Name:{1}", this.Age, this.Name);
            sb.AppendLine();
            foreach (Pet p in this.PetList)
            {
                sb.AppendFormat("PetName:{0}, Weight:{1}", p.Name, p.Weight);
                sb.AppendLine();
            }
            return sb.ToString();
        }
    }
    [Serializable]
    public class Pet : BaseObject
    {
        public string Name;
        public int Weight;
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyList<Pet> pets1 = new MyList<Pet>();
            pets1.Add(new Pet { Weight=60,Name="pp"});
            pets1.Add(new Pet { Weight =80, Name = "bb" });
            Student stu1 = new Student
            {
                Age = 15,
                Name = "ZZW",
                PetList = pets1
            };
            Student stu2 = (Student)stu1.Clone();
            Console.WriteLine("Before modidfy.....");
            Console.WriteLine("Stu1:" + stu1.ToString());
            Console.WriteLine("Stu2:" + stu2.ToString());
            stu2.Age = 66;
            stu2.Name = "jjj";
            foreach (Pet p in stu2.PetList)
            {
                p.Name = "xx";
                p.Weight = 100;
            }
            Console.WriteLine("After Stu2 modidfy.....");
            Console.WriteLine("Stu1:" + stu1.ToString());
            Console.WriteLine("Stu2:" + stu2.ToString());
            Console.ReadKey();
        }
    }

Output:

Before modidfy.....
Stu1:Age:15, Name:ZZW
PetName:pp, Weight:60
PetName:bb, Weight:80

Stu2:Age:15, Name:ZZW
PetName:pp, Weight:60
PetName:bb, Weight:80

After Stu2 modidfy.....
Stu1:Age:15, Name:ZZW
PetName:pp, Weight:60
PetName:bb, Weight:80

Stu2:Age:66, Name:jjj
PetName:xx, Weight:100
PetName:xx, Weight:100

  

 

 

Guess you like

Origin www.cnblogs.com/change-myself/p/10956527.html