当前位置:网站首页>[C] thoroughly understand the deep copy

[C] thoroughly understand the deep copy

2022-04-23 17:08:00 code bean

Every language has the concept of deep copy , In fact, they are all the same , This time from C# Interpretation from the perspective of .

C# There are value types and reference types . Value type , Such as int There are no shallow and deep problems , Direct assignment is over .

Reference type , For example, our custom class . adopt new The way to create ,new What is returned is actually “ The pointer ”,

Or quote , He himself is on the stack , however new The allocated space is on the heap . If you assign a value to a reference directly ,

It's quite a change “ The pointer ” The direction of . Heap memory previously managed by him , It was suspended , Finally, no one pointed to it , Will be recycled by the garbage collection mechanism .

such as , I customize a class .

        public class Box
        {
            public double height;   //  Height 
            public double width;    //  Width 
            
        }

then new Two objects , And will b1 Directly assign to b2

Box b1 = new Box();
Box b2 = new Box();

b2 = b1;
b2.width = 5; // change b2  influence b1
Console.WriteLine(b1.width);

here b2 and b1 Pointing to the same block of memory ,b2 The previously allocated memory is suspended , Finally being GC Recycling .

Then if you don't want to , I want to copy a separate b2(b2 The change of does not affect b1), Then the only way is to copy one by one .

        public static Box FixDeepCopy(double height, double width)
        {
            Box b = new Box();
            b.height = height;
            b.width = width;
            return b;
        }

Here we notice , We haven't changed b The direction of , therefore b It points to yourself at the beginning new Out of memory . Due to the assignment one by one , So at this time, the deep copy is successful .

But it's too much trouble , Different types , To write different deep copy functions , And as classes become more complex , The more complicated the method is .

So the following three methods , Help you with , Observe carefully , In fact, these three methods , In fact, it also copies the member variables one by one ,

It's just a generalization .

Not much said , Go straight to the code :

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace DeepCopyTest
{
    internal class Program
    {
        [Serializable]
        public class Box
        {
            public double height;   //  Height 
            public double width;    //  Width 
            
        }

        public static Box FixDeepCopy(double height, double width)
        {
            Box b = new Box();
            b.height = height;
            b.width = width;
            return b;
        }


        public static T DeepCopyByBin<T>(T obj)
        {
            object retval;
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                // Sequence into a stream 
                bf.Serialize(ms, obj);
                // Sets the position in the current stream to the specified value . That is from SeekOrigin.Begin The offset 0 A place .
                ms.Seek(0, SeekOrigin.Begin);
                // Anti serialization into objects 
                retval = bf.Deserialize(ms);
                ms.Close();
            }
            return (T)retval;
        }


        /// <summary>
        ///  Note that you need to add... To the class [Serializable]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopyByReflect<T>(T obj)
        {
            // If it is a string or value type, it directly returns 
            if (obj is string || obj.GetType().IsValueType) return obj;

            object retval = Activator.CreateInstance(obj.GetType());
            FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            foreach (FieldInfo field in fields)
            {
                try { field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj))); }
                catch { }
            }
            return (T)retval;
        }



        static void Main(string[] args)
        {
            Box b1 = new Box();
            Box b2 = new Box();
            Box b3 = new Box();
            Box b4 = new Box();
            Console.WriteLine(b1.width);

            // The way of direct assignment 
            b2 = b1;
            b2.width = 5; // change b2  influence b1
            Console.WriteLine(b1.width);


            Console.WriteLine("-------------- The way 1----------------------");
            // Deep copy 
            b2 = DeepCopyByBin(b1);
            b2.width = 6; // change b2  No effect b1
            Console.WriteLine(b1.width);


            Console.WriteLine("--------------- The way 2---------------------");       
            // Deep copy 
            b3 = DeepCopyByReflect(b1);
            b3.width = 7; // change b5  No effect b1
            Console.WriteLine(b1.width);

            Console.WriteLine("---------------- The way 3--------------------");
            // Deep copy ( You need to install the package :Newtonsoft.Json)
            b4 = JsonConvert.DeserializeObject<Box>(JsonConvert.SerializeObject(b1)); // A deep clone 
            b4.width = 789; // change b4  No effect b1
            Console.WriteLine(b1.width);


            Console.ReadKey();
        }
    }
}

Summary :

1 Sensory  JsonConvert Most convenient , You need to install a package yourself Newtonsoft.Json( This bag is too common )

JsonConvert.DeserializeObject<Box>(JsonConvert.SerializeObject(b1));

2 Use  BinaryFormatter The way , Note that you need to add a serializable feature to the class [Serializable], Otherwise, the operation will report an error .

It's more direct , Copy the whole memory directly .

3 Finally, reflect this way , Pay attention to , Because you can see it , It uses recursion , To retrieve every object .

If the object is too complex , There may be a problem .

版权声明
本文为[code bean]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231702084859.html