Fastest Way to do Shallow Copy in C#

后端 未结 8 1550
庸人自扰
庸人自扰 2020-12-12 16:20

I wonder what is the fastest way to do shallow copying in C#? I only know there are 2 ways to do shallow copy:

  1. MemberwiseClone
  2. Copy each field one by
相关标签:
8条回答
  • 2020-12-12 17:01

    In fact, MemberwiseClone is usually much better than others, especially for complex type.

    The reason is that:if you manual create a copy, it must call one of the type's constructor, but use memberwise clone, I guess it just copy a block of memory. for those types has very expensive construct actions, memberwise clone is absolutely the best way.

    Onece i wrote such type: {string A = Guid.NewGuid().ToString()}, I found memberwise clone is muct faster than create a new instance and manual assign members.

    The code below's result:

    Manual Copy:00:00:00.0017099

    MemberwiseClone:00:00:00.0009911

    namespace MoeCard.TestConsole
    {
        class Program
        {
            static void Main(string[] args)
            {
                Program p = new Program() { AAA = Guid.NewGuid().ToString(), BBB = 123 };
                Stopwatch sw = Stopwatch.StartNew();
                for (int i = 0; i < 10000; i++)
                {
                    p.Copy1();
                }
                sw.Stop();
                Console.WriteLine("Manual Copy:" + sw.Elapsed);
    
                sw.Restart();
                for (int i = 0; i < 10000; i++)
                {
                    p.Copy2();
                }
                sw.Stop();
                Console.WriteLine("MemberwiseClone:" + sw.Elapsed);
                Console.ReadLine();
            }
    
            public string AAA;
    
            public int BBB;
    
            public Class1 CCC = new Class1();
    
            public Program Copy1()
            {
                return new Program() { AAA = AAA, BBB = BBB, CCC = CCC };
            }
            public Program Copy2()
            {
                return this.MemberwiseClone() as Program;
            }
    
            public class Class1
            {
                public DateTime Date = DateTime.Now;
            }
        }
    
    }
    

    finally, I provide my code here:

        #region 数据克隆
        /// <summary>
        /// 依据不同类型所存储的克隆句柄集合
        /// </summary>
        private static readonly Dictionary<Type, Func<object, object>> CloneHandlers = new Dictionary<Type, Func<object, object>>();
    
        /// <summary>
        /// 根据指定的实例,克隆一份新的实例
        /// </summary>
        /// <param name="source">待克隆的实例</param>
        /// <returns>被克隆的新的实例</returns>
        public static object CloneInstance(object source)
        {
            if (source == null)
            {
                return null;
            }
            Func<object, object> handler = TryGetOrAdd(CloneHandlers, source.GetType(), CreateCloneHandler);
            return handler(source);
        }
    
        /// <summary>
        /// 根据指定的类型,创建对应的克隆句柄
        /// </summary>
        /// <param name="type">数据类型</param>
        /// <returns>数据克隆句柄</returns>
        private static Func<object, object> CreateCloneHandler(Type type)
        {
            return Delegate.CreateDelegate(typeof(Func<object, object>), new Func<object, object>(CloneAs<object>).Method.GetGenericMethodDefinition().MakeGenericMethod(type)) as Func<object, object>;
        }
    
        /// <summary>
        /// 克隆一个类
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        private static object CloneAs<TValue>(object value)
        {
            return Copier<TValue>.Clone((TValue)value);
        }
        /// <summary>
        /// 生成一份指定数据的克隆体
        /// </summary>
        /// <typeparam name="TValue">数据的类型</typeparam>
        /// <param name="value">需要克隆的值</param>
        /// <returns>克隆后的数据</returns>
        public static TValue Clone<TValue>(TValue value)
        {
            if (value == null)
            {
                return value;
            }
            return Copier<TValue>.Clone(value);
        }
    
        /// <summary>
        /// 辅助类,完成数据克隆
        /// </summary>
        /// <typeparam name="TValue">数据类型</typeparam>
        private static class Copier<TValue>
        {
            /// <summary>
            /// 用于克隆的句柄
            /// </summary>
            internal static readonly Func<TValue, TValue> Clone;
    
            /// <summary>
            /// 初始化
            /// </summary>
            static Copier()
            {
                MethodFactory<Func<TValue, TValue>> method = MethodFactory.Create<Func<TValue, TValue>>();
                Type type = typeof(TValue);
                if (type == typeof(object))
                {
                    method.LoadArg(0).Return();
                    return;
                }
                switch (Type.GetTypeCode(type))
                {
                    case TypeCode.Object:
                        if (type.IsClass)
                        {
                            method.LoadArg(0).Call(Reflector.GetMethod(typeof(object), "MemberwiseClone")).Cast(typeof(object), typeof(TValue)).Return();
                        }
                        else
                        {
                            method.LoadArg(0).Return();
                        }
                        break;
                    default:
                        method.LoadArg(0).Return();
                        break;
                }
                Clone = method.Delegation;
            }
    
        }
        #endregion
    
    0 讨论(0)
  • 2020-12-12 17:03

    MemberwiseClone requires less maintenance. I don't know if having default property values helps any, maybe if could ignore items with default values.

    0 讨论(0)
提交回复
热议问题