1. 程式人生 > 實用技巧 >c# 幾種深拷貝方式的比較

c# 幾種深拷貝方式的比較

    public static class Tools
    {
        //利用 BinaryFormatter 實現深拷貝
        public static T DeepCopyByBinary<T>(this T obj)
        {
            T t = default(T);
            IFormatter formatter = new BinaryFormatter();
            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                t = (T)formatter.Deserialize(ms);
            }
            return t;
        }

        //利用 XmlSerializer 實現深拷貝
        public static T DeepCopyByXml<T>(this T obj)
        {
            T t = default(T);
            XmlSerializer xmlserialize = new XmlSerializer(typeof(T));
            using (MemoryStream ms = new MemoryStream())
            {
                xmlserialize.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                t = (T)xmlserialize.Deserialize(ms);
            }
            return t;
        }

        //利用反射實現深拷貝
        public static T DeepCopyByReflection<T>(this T tSource)
        {
            T tResult = Activator.CreateInstance<T>();
            Type sourceType = typeof(T);
            Type resultType = typeof(T);
            var sourcePros = sourceType.GetProperties();
            foreach (var pro in sourcePros)
            {
                var sourceProValue = pro.GetValue(tSource);
                var resultPro = resultType.GetProperty(pro.Name);
                resultPro.SetValue(tResult, sourceProValue);
            }
            return tResult;
        }
    }

            Person p1 = new Person { Id = 1, Name = "wjire" };
            Stopwatch sw1 = new Stopwatch();
            sw1.Start();
            for (int i = 0; i < 100000; i++)
            {
                Person p2 = p1.DeepCopyByBinary();
            }
            sw1.Stop();
            Console.WriteLine($"DeepCopyByBinary 共耗時 {sw1.ElapsedMilliseconds} 毫秒");



            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < 100000; i++)
            {
                Person p2 = p1.DeepCopyByXml();
            }
            sw2.Stop();
            Console.WriteLine($"DeepCopyByXml 共耗時 {sw2.ElapsedMilliseconds} 毫秒");


            Stopwatch sw3 = new Stopwatch();
            sw3.Start();
            for (int i = 0; i < 100000; i++)
            {
                Person p2 = p1.DeepCopyByReflection();
            }
            sw3.Stop();
            Console.WriteLine($"DeepCopyByReflection 共耗時 {sw3.ElapsedMilliseconds} 毫秒");


            //利用 json.net 實現深拷貝
            Stopwatch sw4 = new Stopwatch();
            sw4.Start();
            for (int i = 0; i < 100000; i++)
            {
                Person p2 = JsonConvert.DeserializeObject<Person>(JsonConvert.SerializeObject(p1));
            }
            sw4.Stop();
            Console.WriteLine($"Newtonsoft.Json 共耗時 {sw4.ElapsedMilliseconds} 毫秒");

執行結果:

反射最快!!

    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person(123)
            {
                Id = 1,
                Age = 33,
                Name = "wjire"
            };

            Expression<Func<Person, Person>> exp1 = p => new Person(333) { Id = p.Id, Name = p.Name, Age = p.Age };
            var func1 = exp1.Compile();
            Person p23 = func1(p1);
            Console.WriteLine(p23.Id);



            Console.WriteLine("*****************************");
            ParameterExpression parameterExpression = Expression.Parameter(p1.GetType(), "p"); // 創造了 lambda表示式中的入參: p
            Console.WriteLine(parameterExpression);

            List<MemberBinding> memberBindingList = new List<MemberBinding>();
            foreach (PropertyInfo pro in p1.GetType().GetProperties())
            {
                if (!pro.CanWrite)
                {
                    continue;
                }
                MemberExpression property = Expression.Property(parameterExpression, pro.Name);
                Console.WriteLine(property);// p.Id,p.Name,p.Age

                MemberBinding memberBinding = Expression.Bind(pro, property);
                Console.WriteLine(memberBinding);// p=p.Id,p=p.Name,p=p.Age

                memberBindingList.Add(memberBinding);
            }

            var rr = Expression.New(p1.GetType().GetConstructor(new Type[] { typeof(int) }), Expression.Constant(default(int)));

            MemberInitExpression initExpression = Expression.MemberInit(rr, memberBindingList);
            Console.WriteLine(initExpression);// new Person { Id = p.Id, Name = p.Name, Age = p.Age }

            Expression<Func<Person, Person>> exp = Expression.Lambda<Func<Person, Person>>(initExpression, parameterExpression);
            Console.WriteLine(exp);// p => new Person { Id = p.Id, Name = p.Name, Age = p.Age }

            Func<Person, Person> func = exp.Compile();
            Person p2 = func(p1);

            Console.WriteLine(p2.Name);
            Console.WriteLine(p2.Id);
            Console.WriteLine(p2.Age);
            Console.ReadKey();
        }
    }

    internal class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public int Age { get; set; }


        public Person(int id)
        {
            this.Id = id;
        }
    }