转载

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text; namespace Care.Common
{
    public static class ObjectCopy
    {
        struct Identity
        {
            int _hashcode;
            RuntimeTypeHandle _type;             public Identity(int hashcode, RuntimeTypeHandle type)
            {
                _hashcode = hashcode;
                _type = type;
            }
        }
        //缓存对象复制的方法。
        static Dictionary<Type, Func<object, Dictionary<Identity, object>, object>> methods1 = new Dictionary<Type, Func<object, Dictionary<Identity, object>, object>>();
        static Dictionary<Type, Action<object, Dictionary<Identity, object>, object>> methods2 = new Dictionary<Type, Action<object, Dictionary<Identity, object>, object>>();         static List<FieldInfo> GetSettableFields(Type t)
        {
            return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();
        }         static Func<object, Dictionary<Identity, object>, object> CreateCloneMethod1(Type type, Dictionary<Identity, object> objects)
        {
            Type tmptype;
            var fields = GetSettableFields(type);
            var dm = new DynamicMethod(string.Format("Clone{0}", Guid.NewGuid()), typeof(object), new[] { typeof(object), typeof(Dictionary<Identity, object>) }, true);
            var il = dm.GetILGenerator();
            il.DeclareLocal(type);
            il.DeclareLocal(type);
            il.DeclareLocal(typeof(Identity));
            if (!type.IsArray)
            {
                il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc_1);
                il.Emit(OpCodes.Ldloca_S, );
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Castclass, type);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc_0);
                il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetHashCode"));
                il.Emit(OpCodes.Ldtoken, type);
                il.Emit(OpCodes.Call, typeof(Identity).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(int), typeof(RuntimeTypeHandle) }, null));
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldloc_2);
                il.Emit(OpCodes.Ldloc_1);
                il.Emit(OpCodes.Callvirt, typeof(Dictionary<Identity, object>).GetMethod("Add"));
                foreach (var field in fields)
                {
                    if (!field.FieldType.IsValueType && field.FieldType != typeof(String))
                    {
                        //不符合条件的字段,直接忽略,避免报错。
                        if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||
                            (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))
                            break;
                        il.Emit(OpCodes.Ldloc_1);
                        il.Emit(OpCodes.Ldloc_0);
                        il.Emit(OpCodes.Ldfld, field);
                        il.Emit(OpCodes.Ldarg_1);
                        il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);
                        il.Emit(OpCodes.Stfld, field);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldloc_1);
                        il.Emit(OpCodes.Ldloc_0);
                        il.Emit(OpCodes.Ldfld, field);
                        il.Emit(OpCodes.Stfld, field);
                    }
                }
                for (type = type.BaseType; type != null && type != typeof(object); type = type.BaseType)
                {
                    //只需要查找基类的私有成员,共有或受保护的在派生类中直接被复制过了。
                    fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList();
                    foreach (var field in fields)
                    {
                        if (!field.FieldType.IsValueType && field.FieldType != typeof(String))
                        {
                            //不符合条件的字段,直接忽略,避免报错。
                            if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||
                                (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))
                                break;
                            il.Emit(OpCodes.Ldloc_1);
                            il.Emit(OpCodes.Ldloc_0);
                            il.Emit(OpCodes.Ldfld, field);
                            il.Emit(OpCodes.Ldarg_1);
                            il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);
                            il.Emit(OpCodes.Stfld, field);
                        }
                        else
                        {
                            il.Emit(OpCodes.Ldloc_1);
                            il.Emit(OpCodes.Ldloc_0);
                            il.Emit(OpCodes.Ldfld, field);
                            il.Emit(OpCodes.Stfld, field);
                        }
                    }
                }
            }
            else
            {
                Type arraytype = type.GetElementType();
                var i = il.DeclareLocal(typeof(int));
                var lb1 = il.DefineLabel();
                var lb2 = il.DefineLabel();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Castclass, type);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc_0);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Sub);
                il.Emit(OpCodes.Stloc, i);
                il.Emit(OpCodes.Newarr, arraytype);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc_1);
                il.Emit(OpCodes.Ldloca_S, );
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetHashCode"));
                il.Emit(OpCodes.Ldtoken, type);
                il.Emit(OpCodes.Call, typeof(Identity).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(int), typeof(RuntimeTypeHandle) }, null));
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldloc_2);
                il.Emit(OpCodes.Ldloc_1);
                il.Emit(OpCodes.Callvirt, typeof(Dictionary<Identity, object>).GetMethod("Add"));
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Br, lb1);
                il.MarkLabel(lb2);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Ldelem, arraytype);
                if (!arraytype.IsValueType && arraytype != typeof(String))
                {
                    il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(arraytype), null);
                }
                il.Emit(OpCodes.Stelem, arraytype);
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Sub);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc, i);
                il.MarkLabel(lb1);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Clt);
                il.Emit(OpCodes.Brfalse, lb2);
            }
            il.Emit(OpCodes.Ret);             return (Func<object, Dictionary<Identity, object>, object>)dm.CreateDelegate(typeof(Func<object, Dictionary<Identity, object>, object>));
        }         static Action<object, Dictionary<Identity, object>, object> CreateCloneMethod2(Type type, Dictionary<Identity, object> objects)
        {
            Type tmptype;
            var fields = GetSettableFields(type);
            var dm = new DynamicMethod(string.Format("Copy{0}", Guid.NewGuid()), null, new[] { typeof(object), typeof(Dictionary<Identity, object>), typeof(object) }, true);
            var il = dm.GetILGenerator();
            il.DeclareLocal(type);
            il.DeclareLocal(type);
            il.DeclareLocal(typeof(Identity));
            if (!type.IsArray)
            {
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(OpCodes.Castclass, type);
                il.Emit(OpCodes.Stloc_1);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Castclass, type);
                il.Emit(OpCodes.Stloc_0);
                foreach (var field in fields)
                {
                    if (!field.FieldType.IsValueType && field.FieldType != typeof(String))
                    {
                        //不符合条件的字段,直接忽略,避免报错。
                        if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||
                            (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))
                            break;
                        il.Emit(OpCodes.Ldloc_1);
                        il.Emit(OpCodes.Ldloc_0);
                        il.Emit(OpCodes.Ldfld, field);
                        il.Emit(OpCodes.Ldarg_1);
                        il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);
                        il.Emit(OpCodes.Stfld, field);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldloc_1);
                        il.Emit(OpCodes.Ldloc_0);
                        il.Emit(OpCodes.Ldfld, field);
                        il.Emit(OpCodes.Stfld, field);
                    }
                }
                for (type = type.BaseType; type != null && type != typeof(object); type = type.BaseType)
                {
                    //只需要查找基类的私有成员,共有或受保护的在派生类中直接被复制过了。
                    fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList();
                    foreach (var field in fields)
                    {
                        if (!field.FieldType.IsValueType && field.FieldType != typeof(String))
                        {
                            //不符合条件的字段,直接忽略,避免报错。
                            if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||
                                (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))
                                break;
                            il.Emit(OpCodes.Ldloc_1);
                            il.Emit(OpCodes.Ldloc_0);
                            il.Emit(OpCodes.Ldfld, field);
                            il.Emit(OpCodes.Ldarg_1);
                            il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);
                            il.Emit(OpCodes.Stfld, field);
                        }
                        else
                        {
                            il.Emit(OpCodes.Ldloc_1);
                            il.Emit(OpCodes.Ldloc_0);
                            il.Emit(OpCodes.Ldfld, field);
                            il.Emit(OpCodes.Stfld, field);
                        }
                    }
                }
            }
            else
            {
                Type arraytype = type.GetElementType();
                var i = il.DeclareLocal(typeof(int));
                var lb1 = il.DefineLabel();
                var lb2 = il.DefineLabel();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Castclass, type);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc_0);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Sub);
                il.Emit(OpCodes.Stloc, i);
                il.Emit(OpCodes.Ldarg_2);
                il.Emit(OpCodes.Castclass, type);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc_1);
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Br, lb1);
                il.MarkLabel(lb2);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Ldelem, arraytype);
                if (!arraytype.IsValueType && arraytype != typeof(String))
                {
                    il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(arraytype), null);
                }
                il.Emit(OpCodes.Stelem, arraytype);
                il.Emit(OpCodes.Ldloc, i);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Sub);
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Stloc, i);
                il.MarkLabel(lb1);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Clt);
                il.Emit(OpCodes.Brfalse, lb2);
            }
            il.Emit(OpCodes.Ret);             return (Action<object, Dictionary<Identity, object>, object>)dm.CreateDelegate(typeof(Action<object, Dictionary<Identity, object>, object>));
        }         static T CopyImpl<T>(T source, Dictionary<Identity, object> objects) where T : class
        {
            //为空则直接返回null
            if (source == null)
                return null;             Type type = source.GetType();
            Identity id = new Identity(source.GetHashCode(), type.TypeHandle);
            object result;
            //如果发现曾经复制过,用之前的,从而停止递归复制。
            if (!objects.TryGetValue(id, out result))
            {
                //最后查找对象的复制方法,如果不存在,创建新的。
                Func<object, Dictionary<Identity, object>, object> method;
                if (!methods1.TryGetValue(type, out method))
                {
                    method = CreateCloneMethod1(type, objects);
                    methods1.Add(type, method);
                }
                result = method(source, objects);
            }
            return (T)result;
        }         /// <summary>
        /// 创建对象深度复制的副本
        /// </summary>
        public static T ToObjectCopy<T>(this T source) where T : class
        {
            Type type = source.GetType();
            Dictionary<Identity, object> objects = new Dictionary<Identity, object>();//存放内嵌引用类型的复制链,避免构成一个环。
            Func<object, Dictionary<Identity, object>, object> method;
            if (!methods1.TryGetValue(type, out method))
            {
                method = CreateCloneMethod1(type, objects);
                methods1.Add(type, method);
            }
            return (T)method(source, objects);
        }         /// <summary>
        /// 将source对象的所有属性复制到target对象中,深度复制
        /// </summary>
        public static void ObjectCopyTo<T>(this T source, T target) where T : class
        {
            if (target == null)
                throw new Exception("将要复制的目标未初始化");
            Type type = source.GetType();
            if (type != target.GetType())
                throw new Exception("要复制的对象类型不同,无法复制");
            Dictionary<Identity, object> objects = new Dictionary<Identity, object>();//存放内嵌引用类型的复制链,避免构成一个环。
            objects.Add(new Identity(source.GetHashCode(), type.TypeHandle), source);
            Action<object, Dictionary<Identity, object>, object> method;
            if (!methods2.TryGetValue(type, out method))
            {
                method = CreateCloneMethod2(type, objects);
                methods2.Add(type, method);
            }
            method(source, objects, target);
        }
    }
}

C# 对象深度拷贝的更多相关文章

  1. java对象深度拷贝

    如何利用序列化来完成对象的拷贝呢?在内存中通过字节流的拷贝是比较容易实现的.把母对象写入到一个字节流中,再从字节流中将其读出来,这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的 ...

  2. vue 数组、对象 深度拷贝和赋值

    由于此对象的引用类型指向的都是一个地址(除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝) 数组: let a = [11,22,33]; let b = a; / ...

  3. C# Lambda快速深度拷贝

    背景:今天上班在班车上和一个同事讨论有关C#拷贝效率的问题,聊到了多种深度拷贝方法,其中就提到了一种Lambda表达式拷贝的方法,这位同事说这种深度拷贝快是快但是如果对象里面再嵌入对象就不能深度拷贝了 ...

  4. c#:如何处理对对象进行深度拷贝

    /// <summary> /// 对对象进行深度拷贝 /// </summary> /// <param name="obj"></pa ...

  5. javascript中对数组对象的深度拷贝

    在前端开发的某些逻辑中,经常需要对现有的js对象创建副本,避免污染原始数据的情况. 如果是简单的一维数组对象,可以使用两个原生方法: 1.splice var arr1 = ['a', 'b', 'c ...

  6. JSON.parse(JSON.stringify()) 实现对对象的深度拷贝,从而互不影响

    JSON.parse(JSON.stringify({"key": "value"})) 根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字 ...

  7. C#深度拷贝和浅度拷贝方法

    C#浅度拷贝多用于值类型的复制,即 int a=1;int b=a; 设置b=2后不会影响a的值. 但如果对于引用类型class a=new class(); class b=a; 设置b.name= ...

  8. 【转】Java如何克隆集合——深度拷贝ArrayList和HashSet

    原文网址:http://blog.csdn.net/cool_sti/article/details/21658521 原英文链接:http://javarevisited.blogspot.hk/2 ...

  9. String 类的实现(2)深度拷贝详解

    我们已经知道了浅拷贝存在的问题,即多次析构同一空间.这个问题是类的成员函数引起的,就是前面浅拷贝里相当于编译器自动合成的函数,确切的说,浅拷贝里的问题是由隐士拷贝构造函数和隐士赋值运算符引起的. 拷贝 ...

随机推荐

  1. 大熊君大话NodeJS之------Net模块

    一,开篇分析 从今天开始,我们来深入具体的模块学习,这篇文章是这个系列(大熊君大话NodeJS)文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中, 对NodeJS也有一个基本的认识,没事 ...

  2. Python XML解析(转载)

    Python XML解析 什么是XML? XML 指可扩展标记语言(eXtensible Markup Language). 你可以通过本站学习XML教程 XML 被设计用来传输和存储数据. XML是 ...

  3. 老项目的#iPhone6与iPhone6Plus适配#LaunchImage适配

    本文永久地址为 http://www.cnblogs.com/ChenYilong/p/4020384.html,转载请注明出处.  Evernote印象笔记链接:https://www.everno ...

  4. 清北国庆day1 (脑)残

    (留坑) /* 不知道为什要找的循环节TM这么长 */ #include<cstdio> #include<cstdlib> #include<cstring> u ...

  5. hessian接口参数,子类与父类不能有同名字段解决方法

    hessian默认是使用 com.caucho.hessian.io.JavaSerializer 序列化,同名字段子类字段值被赋值两次,最终用父类null值赋给了子类同名字段,解决方法就是 指定序列 ...

  6. IDEA之web项目(maven项目)创建

    1.下载IDEA付费版,有30天的试用期,免费版创建不了web项目(导入不了tomcat). 网址:IntelliJ IDEA :: Download Latest Version of Intell ...

  7. 获取action name在asp.net mvc

    Update for MVC 3 ViewContext.Controller.ValueProvider.GetValue("action").RawValue ViewCont ...

  8. DOM的相关优化

    为什么要进行DOM优化? DOM对象本身也是一个js对象,所以严格来说,并不是操作这个对象慢,而是说操作了这个对象后,会触发一些浏览器行为,比如布局(layout)和绘制(paint). 首先先说一些 ...

  9. laravel打印sql语句

    打印sql语句,直接在你执行SQL语句后输出 方法一: $queries = DB::getQueryLog(); $a = end($queries); $tmp = str_replace('?' ...

  10. vSphere、Hyper-V与XenServer 你选哪个?

    vSphere.Hyper-V与XenServer 你选哪个? 当在VMware vSphere.Microsoft Hyper-V与Citrix Systems XenServer之间做出选择时,v ...