Skip to content
标签
欢迎扫码关注公众号

C# 两种深拷贝方法效率比较

CSDN简书 上都看到一种通过 二进制的序列化和反序列化 来实现深拷贝的方式。

感觉这种方式应该比通过反射的方式更快,然而写了点代码测试了之后,结果大出所料。(下面测试中使用的两种实现均来自 这篇博客

csharp
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;

namespace DeepCopyTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int loop = 10 * 10000;
            var staff = new Staff()
            {
                FirstName = "佳佳",
                LastName = "刘",
                Site = "liujiajia.me",
            };

            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < loop; i++)
            {
                _ = DeepCopyByReflect(staff);
            }
            sw1.Stop();
            Console.WriteLine($"通过 DeepCopyByReflect 方法创建深拷贝耗费 {sw1.ElapsedMilliseconds} ms");

            sw1.Reset();
            sw1.Start();
            for (int i = 0; i < loop; i++)
            {
                _ = DeepCopyByBin(staff);
            }
            sw1.Stop();
            Console.WriteLine($"通过 DeepCopyByBin 方法创建深拷贝耗费 {sw1.ElapsedMilliseconds} ms");

            Console.ReadLine();
        }

        /// <summary>
        /// 深拷贝,通过序列化与反序列化实现
        /// </summary>
        /// <typeparam name="T">深拷贝的类类型</typeparam>
        /// <param name="obj">深拷贝的类对象</param>
        /// <returns></returns>
        public static T DeepCopyByBin<T>(T obj)
        {
            object retval;
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                //序列化成流
                bf.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                //反序列化成对象
                retval = bf.Deserialize(ms);
                ms.Close();
            }
            return (T)retval;
        }

        /// <summary>
        /// 深拷贝,通过反射实现
        /// </summary>
        /// <typeparam name="T">深拷贝的类类型</typeparam>
        /// <param name="obj">深拷贝的类对象</param>
        /// <returns></returns>
        public static T DeepCopyByReflect<T>(T obj)
        {
            //如果是字符串或值类型则直接返回
            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;
        }
    }

    [Serializable]
    class Staff
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Site { get; set; }
    }
}

上述代码输出如下:

txt
通过 DeepCopyByReflect 方法创建深拷贝耗费 87 ms
通过 DeepCopyByBin 方法创建深拷贝耗费 955 ms

可以发现通过 反射 的实现比通过 二进制序列化反序列化 的实现效率高 10 倍以上。

2020-05-12 追记

最近发现在有数组/列表属性时,上文的 DeepCopyByReflect 方法会报异常。

另外新增了一种通过 JSON 的实现。
详情见 => C# 深拷贝方法效率比较(2)

Page Layout Max Width

Adjust the exact value of the page width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the page layout
A ranged slider for user to choose and customize their desired width of the maximum width of the page layout can go.

Content Layout Max Width

Adjust the exact value of the document content width of VitePress layout to adapt to different reading needs and screens.

Adjust the maximum width of the content layout
A ranged slider for user to choose and customize their desired width of the maximum width of the content layout can go.