C# 对象深度拷贝
转载
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# 对象深度拷贝的更多相关文章
- java对象深度拷贝
如何利用序列化来完成对象的拷贝呢?在内存中通过字节流的拷贝是比较容易实现的.把母对象写入到一个字节流中,再从字节流中将其读出来,这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的 ...
- vue 数组、对象 深度拷贝和赋值
由于此对象的引用类型指向的都是一个地址(除了基本类型跟null,对象之间的赋值,只是将地址指向同一个,而不是真正意义上的拷贝) 数组: let a = [11,22,33]; let b = a; / ...
- C# Lambda快速深度拷贝
背景:今天上班在班车上和一个同事讨论有关C#拷贝效率的问题,聊到了多种深度拷贝方法,其中就提到了一种Lambda表达式拷贝的方法,这位同事说这种深度拷贝快是快但是如果对象里面再嵌入对象就不能深度拷贝了 ...
- c#:如何处理对对象进行深度拷贝
/// <summary> /// 对对象进行深度拷贝 /// </summary> /// <param name="obj"></pa ...
- javascript中对数组对象的深度拷贝
在前端开发的某些逻辑中,经常需要对现有的js对象创建副本,避免污染原始数据的情况. 如果是简单的一维数组对象,可以使用两个原生方法: 1.splice var arr1 = ['a', 'b', 'c ...
- JSON.parse(JSON.stringify()) 实现对对象的深度拷贝,从而互不影响
JSON.parse(JSON.stringify({"key": "value"})) 根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字 ...
- C#深度拷贝和浅度拷贝方法
C#浅度拷贝多用于值类型的复制,即 int a=1;int b=a; 设置b=2后不会影响a的值. 但如果对于引用类型class a=new class(); class b=a; 设置b.name= ...
- 【转】Java如何克隆集合——深度拷贝ArrayList和HashSet
原文网址:http://blog.csdn.net/cool_sti/article/details/21658521 原英文链接:http://javarevisited.blogspot.hk/2 ...
- String 类的实现(2)深度拷贝详解
我们已经知道了浅拷贝存在的问题,即多次析构同一空间.这个问题是类的成员函数引起的,就是前面浅拷贝里相当于编译器自动合成的函数,确切的说,浅拷贝里的问题是由隐士拷贝构造函数和隐士赋值运算符引起的. 拷贝 ...
随机推荐
- dubbo框架----探索-大型系统架构设计(图解)
对于高并发系统的架构要求: 1. 负载均衡 2.高并发 3.高可用 4.面向服务架构 (Dubbo框架使用) 5.分布式缓存 (redis分布式缓存) 6.分布式全文检索 (solr分分布式全文检索) ...
- 老项目的#iPhone6与iPhone6Plus适配#LaunchImage适配
本文永久地址为 http://www.cnblogs.com/ChenYilong/p/4020384.html,转载请注明出处. Evernote印象笔记链接:https://www.everno ...
- ECshop安装及报错解决方案总结
一.安装ECshop ECShop是一款B2C独立网店系统 ,适合企业及个人快速构建个性化网上商店.系统是基于PHP语言及MYSQL数据库构架开发的跨平台开源程序.2006年3月推出以来1.0版以来, ...
- Hadoop 之Impala
impala 是基于hive的大数据实时分析查询引擎,直接使用Hive的元数据库metadata意味着impala元数据都存储在hive的metadstore中并且impala兼容hive的 sql解 ...
- javascript高级程序设计---拖拉事件
拖拉事件 拖拉指的是,用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里. 拖拉的对象有好几种,包括Element节点.图片.链接.选中的文字等等.在HTML网页中, ...
- HDU 4791 Alice's Print Service(2013长沙区域赛现场赛A题)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4791 解题报告:打印店提供打印纸张服务,需要收取费用,输入格式是s1 p1 s2 p2 s3 p3.. ...
- 总结六条对我们学习Linux系统有用的忠告
接触linux需要的是端正自己的态度,这个玩意可不是一天两天就能拿得下的.学习个基础,能装系统.能装常见服务.能编译.能配置存储空间.能配置系统参数.能简单查看系统负载等基本够用.但这些只保证能做机房 ...
- VVDocumenter升级后不能使用问题
VVDocumenter-Xcode是Xcode上一款快速添加标准注释,并可以自动生成文档的插件.有了VVDocumenter-Xcode,规范化的注释,只需要输入三个斜线“///”就可以搞定,非常方 ...
- [BZOJ4016][FJOI2014]最短路径树问题
[BZOJ4016][FJOI2014]最短路径树问题 试题描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长 ...
- php源码安全加密之PHP混淆算法.
php源码安全加密的前世今生,本想发在教程区中.不知道怎么发,就写在这里面吧.PHP加密,解密是一直的话题,本人菜鸟,今天就简单向大家介绍一下并说说其中原理.提供一些加密的混淆算法.一\PHP的加密总 ...