.net 拷贝方法

在.net中通常拷贝方法有如下几种:

1.浅拷贝

实现方式:

this.MemberwiseClone();

2.深拷贝

实现方式:

 MemoryStream memoryStream = newMemoryStream();

 BinaryFormatter formatter = newBinaryFormatter();

 formatter.Serialize(memoryStream, this);

 memoryStream.Position = 0;

 formatter.Deserialize(memoryStream);

3.另类拷贝:两个对象都已存在,只将其公共数据复制过去

实现方式:利用动态代码的得反射方法,然后将所有公共数据复制

引用地址:Dynamic Code Generation

 

1.DynamicMethodCompiler.cs

using System;
using System.Reflection;
using System.Reflection.Emit;

namespace DynamicCompilationSpike
{
    public delegate object GetHandler(object source);
    public delegate void SetHandler(object source, object value);
    public delegate object InstantiateObjectHandler();

    public sealed class DynamicMethodCompiler
    {
        // DynamicMethodCompiler
        private DynamicMethodCompiler() { }

        // CreateInstantiateObjectDelegate
        internal static InstantiateObjectHandler CreateInstantiateObjectHandler(Type type)
        {
            ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
            if (constructorInfo == null)
            {
                throw new ApplicationException(string.Format("The type {0} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).", type));
            }

            DynamicMethod dynamicMethod = new DynamicMethod("InstantiateObject", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(object), null, type, true);
            ILGenerator generator = dynamicMethod.GetILGenerator();
            generator.Emit(OpCodes.Newobj, constructorInfo);
            generator.Emit(OpCodes.Ret);
            return (InstantiateObjectHandler)dynamicMethod.CreateDelegate(typeof(InstantiateObjectHandler));
        }
        
        // CreateGetDelegate
        internal static GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo)
        {
            MethodInfo getMethodInfo = propertyInfo.GetGetMethod(true);
            DynamicMethod dynamicGet = CreateGetDynamicMethod(type);
            ILGenerator getGenerator = dynamicGet.GetILGenerator();

            getGenerator.Emit(OpCodes.Ldarg_0);
            getGenerator.Emit(OpCodes.Call, getMethodInfo);
            BoxIfNeeded(getMethodInfo.ReturnType, getGenerator);
            getGenerator.Emit(OpCodes.Ret);

            return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
        }

        // CreateGetDelegate
        internal static GetHandler CreateGetHandler(Type type, FieldInfo fieldInfo)
        {
            DynamicMethod dynamicGet = CreateGetDynamicMethod(type);
            ILGenerator getGenerator = dynamicGet.GetILGenerator();

            getGenerator.Emit(OpCodes.Ldarg_0);
            getGenerator.Emit(OpCodes.Ldfld, fieldInfo);
            BoxIfNeeded(fieldInfo.FieldType, getGenerator);
            getGenerator.Emit(OpCodes.Ret);

            return (GetHandler)dynamicGet.CreateDelegate(typeof(GetHandler));
        }

        // CreateSetDelegate
        internal static SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo)
        {
            MethodInfo setMethodInfo = propertyInfo.GetSetMethod(true);
            DynamicMethod dynamicSet = CreateSetDynamicMethod(type);
            ILGenerator setGenerator = dynamicSet.GetILGenerator();

            setGenerator.Emit(OpCodes.Ldarg_0);
            setGenerator.Emit(OpCodes.Ldarg_1);
            UnboxIfNeeded(setMethodInfo.GetParameters()[0].ParameterType, setGenerator);
            setGenerator.Emit(OpCodes.Call, setMethodInfo);
            setGenerator.Emit(OpCodes.Ret);

            return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
        }

        // CreateSetDelegate
        internal static SetHandler CreateSetHandler(Type type, FieldInfo fieldInfo)
        {
            DynamicMethod dynamicSet = CreateSetDynamicMethod(type);
            ILGenerator setGenerator = dynamicSet.GetILGenerator();

            setGenerator.Emit(OpCodes.Ldarg_0);
            setGenerator.Emit(OpCodes.Ldarg_1);
            UnboxIfNeeded(fieldInfo.FieldType, setGenerator);
            setGenerator.Emit(OpCodes.Stfld, fieldInfo);
            setGenerator.Emit(OpCodes.Ret);

            return (SetHandler)dynamicSet.CreateDelegate(typeof(SetHandler));
        }

        // CreateGetDynamicMethod
        private static DynamicMethod CreateGetDynamicMethod(Type type)
        {
            return new DynamicMethod("DynamicGet", typeof(object), new Type[] { typeof(object) }, type, true);
        }

        // CreateSetDynamicMethod
        private static DynamicMethod CreateSetDynamicMethod(Type type)
        {
            return new DynamicMethod("DynamicSet", typeof(void), new Type[] { typeof(object), typeof(object) }, type, true);
        }

        // BoxIfNeeded
        private static void BoxIfNeeded(Type type, ILGenerator generator)
        {
            if (type.IsValueType)
            {
                generator.Emit(OpCodes.Box, type);
            }
        }

        // UnboxIfNeeded
        private static void UnboxIfNeeded(Type type, ILGenerator generator)
        {
            if (type.IsValueType)
            {
                generator.Emit(OpCodes.Unbox_Any, type);
            }
        }
    }
}

2.FastClone.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using DynamicCompilationSpike;

namespace DynamicCompilationSpike;
{
    public class FastClone
    {
        private static Dictionary<Type, FastType> __propertyCache = new Dictionary<Type, FastType>();


        /// <summary>
        /// 添加需要克隆的类型
        /// </summary>
        /// <param name="type"></param>
        /// <param name="copyPrivate">是否拷贝私有,只读字段数据</param>
        public static void AddCloneType(Type type,bool copyPrivate)
        {
            if (!__propertyCache.ContainsKey(type))
                __propertyCache.Add(type, new FastType(type,copyPrivate));

        }

        /// <summary>
        /// 只克隆对象所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="src"></param>
        /// <param name="target"></param>
        public static void Clone<T>(T src, T target) 
        {
            FastType fastType = __propertyCache[typeof(T)];
            foreach (MemberInfo varMember in fastType.Members)
            {
                if (!fastType.Sets.ContainsKey(varMember)) continue;
                SetHandler setHandler=  fastType.Sets[varMember];

                if (!fastType.Gets.ContainsKey(varMember)) continue;
                GetHandler getHandler = fastType.Gets[varMember];

                setHandler(target, getHandler(src));
            }
        }
    }

    internal class FastType
    {
        private Type _type;

        internal Type Type
        {
            get { return _type; }
        }

        private Dictionary<MemberInfo, SetHandler> _cacheSets = new Dictionary<MemberInfo, SetHandler>();

        public Dictionary<MemberInfo, SetHandler> Sets
        {
            get { return _cacheSets; }
        }
        private Dictionary<MemberInfo, GetHandler> _cacheGets = new Dictionary<MemberInfo, GetHandler>();

        public Dictionary<MemberInfo, GetHandler> Gets
        {
            get { return _cacheGets; }
        }

        private List<MemberInfo> _cacheMember = new List<MemberInfo>();

        public List<MemberInfo> Members
        {
            get { return _cacheMember; }
        }

        internal FastType(Type type,bool copyPrivate)
        {
            _type = type;

            foreach (PropertyInfo varProperty in type.GetProperties())
            {
                SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, varProperty);
                GetHandler getHandler = DynamicMethodCompiler.CreateGetHandler(type, varProperty);

                if (copyPrivate)
                {
                    _cacheSets.Add(varProperty, setHandler);
                    _cacheGets.Add(varProperty, getHandler);
                }
                else
                {
                    if (varProperty.CanWrite) _cacheSets.Add(varProperty, setHandler);
                    if (varProperty.CanRead) _cacheGets.Add(varProperty, getHandler);
                }
               
                _cacheMember.Add(varProperty);
            }

            foreach (FieldInfo varField in type.GetFields())
            {
                SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, varField);
                GetHandler getHandler = DynamicMethodCompiler.CreateGetHandler(type, varField);

                if (copyPrivate)
                {
                    _cacheSets.Add(varField, setHandler);
                }
                else
                {
                    if (!(varField.IsInitOnly || varField.IsLiteral)) _cacheSets.Add(varField, setHandler);
                }                
                _cacheGets.Add(varField, getHandler);
                _cacheMember.Add(varField);
            }
        }
    }
}

3.program.cs

using System;
using System.Collections.Generic;
using System.Text;
using CodeTimer1;

namespace DynamicCompilationSpike
{
    class program
    {
        public static void  Main()
        {
            InfoTest info= new InfoTest("info1");
            info.IntValue = 100;
            info.LongValue = 20000;
            info.StringValue = "中华人民共和国!";
            info.DateTimeValue = DateTime.Now.AddHours(24);
            info.DecimalValue = 600;

            InfoTest info2=null;
            long i= 0;

            CodeTimer.Time("copy:", 1000000, delegate {
                info2 = new InfoTest(i.ToString());
                i++;
                info2.IntValue = info.IntValue;
                info2.LongValue = info.LongValue;
                info2.StringValue = info.StringValue;
                info2.DateTimeValue = info.DateTimeValue;
                info2.DecimalValue = info.DecimalValue;
                info2.LastName = info.LastName;
            });
            Console.WriteLine(info2);

            InfoTest info3 = null;
            FastClone.AddCloneType(typeof(InfoTest),false);
            i = 0;
            CodeTimer.Time("clone:", 1000000, delegate
            {
                info3= new InfoTest(i.ToString());
                i++;
                FastClone.Clone<InfoTest>(info, info3);
            });
            Console.WriteLine(info3);
            Console.ReadKey();

        }
    }
}

4.CodeTimer代码地址

5.性能参数对比

image

posted @ 2009-12-17 20:23  不可以  阅读(866)  评论(0编辑  收藏  举报
使用Live Messenger联系我
关闭