C# .NET 常見DeepCopy 深度拷貝的性能對比

先上結論

Method Mean Error StdDev Gen0 Gen1 Allocated
JSONConvert 2,273.02 ns 43.758 ns 52.091 ns 0.6599 - 4160 B
Reflection 1,009.13 ns 10.110 ns 8.442 ns 0.0629 - 400 B
BinaryFormatter 8,146.04 ns 85.914 ns 67.076 ns 1.6022 0.0153 10088 B
Expression 14.70 ns 0.315 ns 0.430 ns 0.0063 - 40 B

由測試得出結論:
1 首選Expression表達式樹,性能大幅領先於反射,耗時僅爲反射的1/70
2 反射,最常用的深度拷貝方法,書寫比較簡單
3 JSONConvert,最簡答的寫法,適用於偶爾需要深度拷貝的時候使用
4 BinaryFormatter,不推薦,需要在類上加上序列化聲明,並且在.NET 5.0中該方法已經被微軟聲明爲過期.

代碼

 public static class DeepCopyUtil
    {
        /// <summary>
        /// Json深度拷貝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopyJson<T>(T obj)
        {
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
        }

        /// <summary>
        /// 反射深度拷貝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T DeepCopyReflection<T>(T obj)
        {
            var type = obj.GetType();
            object o = Activator.CreateInstance(type);
            System.Reflection.PropertyInfo[] PI = type.GetProperties();
            for (int i = 0; i < PI.Count(); i++)
            {
                System.Reflection.PropertyInfo P = PI[i];
                P.SetValue(o, P.GetValue(obj));
            }
            return (T)o;
        }


        public static T DeepCopyMemory<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;
        }

        public static class TransExp<TIn, TOut>
        {
            private static readonly Func<TIn, TOut> cache = GetFunc();
            private static Func<TIn, TOut> GetFunc()
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();

                foreach (var item in typeof(TOut).GetProperties())
                {
                    if (!item.CanWrite) continue;
                    MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }

                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[] { parameterExpression });

                return lambda.Compile();
            }

            public static TOut Trans(TIn tIn)
            {
                return cache(tIn);
            }
        }
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章