最高效率的對象深拷貝通用方法

[csharp] view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Reflection;  
  5. using System.Reflection.Emit;  
  6. using System.Text;  
  7.   
  8.   
  9. namespace Care.Common  
  10. {  
  11.     public static class ObjectCopy  
  12.     {  
  13.         struct Identity  
  14.         {  
  15.             int _hashcode;  
  16.             RuntimeTypeHandle _type;  
  17.   
  18.   
  19.             public Identity(int hashcode, RuntimeTypeHandle type)  
  20.             {  
  21.                 _hashcode = hashcode;  
  22.                 _type = type;  
  23.             }  
  24.         }  
  25.         //緩存對象複製的方法。  
  26.         static Dictionary<Type, Func<object, Dictionary<Identity, object>, object>> methods1 = new Dictionary<Type, Func<object, Dictionary<Identity, object>, object>>();  
  27.         static Dictionary<Type, Action<object, Dictionary<Identity, object>, object>> methods2 = new Dictionary<Type, Action<object, Dictionary<Identity, object>, object>>();  
  28.   
  29.   
  30.         static List<FieldInfo> GetSettableFields(Type t)  
  31.         {  
  32.             return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList();  
  33.         }  
  34.   
  35.   
  36.         static Func<object, Dictionary<Identity, object>, object> CreateCloneMethod1(Type type, Dictionary<Identity, object> objects)  
  37.         {  
  38.             Type tmptype;  
  39.             var fields = GetSettableFields(type);  
  40.             var dm = new DynamicMethod(string.Format("Clone{0}", Guid.NewGuid()), typeof(object), new[] { typeof(object), typeof(Dictionary<Identity, object>) }, true);  
  41.             var il = dm.GetILGenerator();  
  42.             il.DeclareLocal(type);  
  43.             il.DeclareLocal(type);  
  44.             il.DeclareLocal(typeof(Identity));  
  45.             if (!type.IsArray)  
  46.             {  
  47.                 il.Emit(OpCodes.Newobj, type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));  
  48.                 il.Emit(OpCodes.Dup);  
  49.                 il.Emit(OpCodes.Stloc_1);  
  50.                 il.Emit(OpCodes.Ldloca_S, 2);  
  51.                 il.Emit(OpCodes.Ldarg_0);  
  52.                 il.Emit(OpCodes.Castclass, type);  
  53.                 il.Emit(OpCodes.Dup);  
  54.                 il.Emit(OpCodes.Stloc_0);  
  55.                 il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetHashCode"));  
  56.                 il.Emit(OpCodes.Ldtoken, type);  
  57.                 il.Emit(OpCodes.Call, typeof(Identity).GetConstructor(BindingFlags.Instance | BindingFlags.Public, nullnew[] { typeof(int), typeof(RuntimeTypeHandle) }, null));  
  58.                 il.Emit(OpCodes.Ldarg_1);  
  59.                 il.Emit(OpCodes.Ldloc_2);  
  60.                 il.Emit(OpCodes.Ldloc_1);  
  61.                 il.Emit(OpCodes.Callvirt, typeof(Dictionary<Identity, object>).GetMethod("Add"));  
  62.                 foreach (var field in fields)  
  63.                 {  
  64.                     if (!field.FieldType.IsValueType && field.FieldType != typeof(String))  
  65.                     {  
  66.                         //不符合條件的字段,直接忽略,避免報錯。  
  67.                         if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > 1 || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||  
  68.                             (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))  
  69.                             break;  
  70.                         il.Emit(OpCodes.Ldloc_1);  
  71.                         il.Emit(OpCodes.Ldloc_0);  
  72.                         il.Emit(OpCodes.Ldfld, field);  
  73.                         il.Emit(OpCodes.Ldarg_1);  
  74.                         il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);  
  75.                         il.Emit(OpCodes.Stfld, field);  
  76.                     }  
  77.                     else  
  78.                     {  
  79.                         il.Emit(OpCodes.Ldloc_1);  
  80.                         il.Emit(OpCodes.Ldloc_0);  
  81.                         il.Emit(OpCodes.Ldfld, field);  
  82.                         il.Emit(OpCodes.Stfld, field);  
  83.                     }  
  84.                 }  
  85.                 for (type = type.BaseType; type != null && type != typeof(object); type = type.BaseType)  
  86.                 {  
  87.                     //只須要查找基類的私有成員,共有或受保護的在派生類中直接被複制過了。  
  88.                     fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList();  
  89.                     foreach (var field in fields)  
  90.                     {  
  91.                         if (!field.FieldType.IsValueType && field.FieldType != typeof(String))  
  92.                         {  
  93.                             //不符合條件的字段,直接忽略,避免報錯。  
  94.                             if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > 1 || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||  
  95.                                 (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))  
  96.                                 break;  
  97.                             il.Emit(OpCodes.Ldloc_1);  
  98.                             il.Emit(OpCodes.Ldloc_0);  
  99.                             il.Emit(OpCodes.Ldfld, field);  
  100.                             il.Emit(OpCodes.Ldarg_1);  
  101.                             il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);  
  102.                             il.Emit(OpCodes.Stfld, field);  
  103.                         }  
  104.                         else  
  105.                         {  
  106.                             il.Emit(OpCodes.Ldloc_1);  
  107.                             il.Emit(OpCodes.Ldloc_0);  
  108.                             il.Emit(OpCodes.Ldfld, field);  
  109.                             il.Emit(OpCodes.Stfld, field);  
  110.                         }  
  111.                     }  
  112.                 }  
  113.             }  
  114.             else  
  115.             {  
  116.                 Type arraytype = type.GetElementType();  
  117.                 var i = il.DeclareLocal(typeof(int));  
  118.                 var lb1 = il.DefineLabel();  
  119.                 var lb2 = il.DefineLabel();  
  120.                 il.Emit(OpCodes.Ldarg_0);  
  121.                 il.Emit(OpCodes.Castclass, type);  
  122.                 il.Emit(OpCodes.Dup);  
  123.                 il.Emit(OpCodes.Stloc_0);  
  124.                 il.Emit(OpCodes.Ldlen);  
  125.                 il.Emit(OpCodes.Dup);  
  126.                 il.Emit(OpCodes.Ldc_I4_1);  
  127.                 il.Emit(OpCodes.Sub);  
  128.                 il.Emit(OpCodes.Stloc, i);  
  129.                 il.Emit(OpCodes.Newarr, arraytype);  
  130.                 il.Emit(OpCodes.Dup);  
  131.                 il.Emit(OpCodes.Stloc_1);  
  132.                 il.Emit(OpCodes.Ldloca_S, 2);  
  133.                 il.Emit(OpCodes.Ldloc_0);  
  134.                 il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("GetHashCode"));  
  135.                 il.Emit(OpCodes.Ldtoken, type);  
  136.                 il.Emit(OpCodes.Call, typeof(Identity).GetConstructor(BindingFlags.Instance | BindingFlags.Public, nullnew[] { typeof(int), typeof(RuntimeTypeHandle) }, null));  
  137.                 il.Emit(OpCodes.Ldarg_1);  
  138.                 il.Emit(OpCodes.Ldloc_2);  
  139.                 il.Emit(OpCodes.Ldloc_1);  
  140.                 il.Emit(OpCodes.Callvirt, typeof(Dictionary<Identity, object>).GetMethod("Add"));  
  141.                 il.Emit(OpCodes.Ldloc, i);  
  142.                 il.Emit(OpCodes.Br, lb1);  
  143.                 il.MarkLabel(lb2);  
  144.                 il.Emit(OpCodes.Dup);  
  145.                 il.Emit(OpCodes.Ldloc, i);  
  146.                 il.Emit(OpCodes.Ldloc_0);  
  147.                 il.Emit(OpCodes.Ldloc, i);  
  148.                 il.Emit(OpCodes.Ldelem, arraytype);  
  149.                 if (!arraytype.IsValueType && arraytype != typeof(String))  
  150.                 {  
  151.                     il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(arraytype), null);  
  152.                 }  
  153.                 il.Emit(OpCodes.Stelem, arraytype);  
  154.                 il.Emit(OpCodes.Ldloc, i);  
  155.                 il.Emit(OpCodes.Ldc_I4_1);  
  156.                 il.Emit(OpCodes.Sub);  
  157.                 il.Emit(OpCodes.Dup);  
  158.                 il.Emit(OpCodes.Stloc, i);  
  159.                 il.MarkLabel(lb1);  
  160.                 il.Emit(OpCodes.Ldc_I4_0);  
  161.                 il.Emit(OpCodes.Clt);  
  162.                 il.Emit(OpCodes.Brfalse, lb2);  
  163.             }  
  164.             il.Emit(OpCodes.Ret);  
  165.   
  166.   
  167.             return (Func<object, Dictionary<Identity, object>, object>)dm.CreateDelegate(typeof(Func<object, Dictionary<Identity, object>, object>));  
  168.         }  
  169.   
  170.         static Action<object, Dictionary<Identity, object>, object> CreateCloneMethod2(Type type, Dictionary<Identity, object> objects)  
  171.         {  
  172.             Type tmptype;  
  173.             var fields = GetSettableFields(type);  
  174.             var dm = new DynamicMethod(string.Format("Copy{0}", Guid.NewGuid()), nullnew[] { typeof(object), typeof(Dictionary<Identity, object>), typeof(object) }, true);  
  175.             var il = dm.GetILGenerator();  
  176.             il.DeclareLocal(type);  
  177.             il.DeclareLocal(type);  
  178.             il.DeclareLocal(typeof(Identity));  
  179.             if (!type.IsArray)  
  180.             {  
  181.                 il.Emit(OpCodes.Ldarg_2);  
  182.                 il.Emit(OpCodes.Castclass, type);  
  183.                 il.Emit(OpCodes.Stloc_1);  
  184.                 il.Emit(OpCodes.Ldarg_0);  
  185.                 il.Emit(OpCodes.Castclass, type);  
  186.                 il.Emit(OpCodes.Stloc_0);  
  187.                 foreach (var field in fields)  
  188.                 {  
  189.                     if (!field.FieldType.IsValueType && field.FieldType != typeof(String))  
  190.                     {  
  191.                         //不符合條件的字段,直接忽略,避免報錯。  
  192.                         if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > 1 || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||  
  193.                             (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))  
  194.                             break;  
  195.                         il.Emit(OpCodes.Ldloc_1);  
  196.                         il.Emit(OpCodes.Ldloc_0);  
  197.                         il.Emit(OpCodes.Ldfld, field);  
  198.                         il.Emit(OpCodes.Ldarg_1);  
  199.                         il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);  
  200.                         il.Emit(OpCodes.Stfld, field);  
  201.                     }  
  202.                     else  
  203.                     {  
  204.                         il.Emit(OpCodes.Ldloc_1);  
  205.                         il.Emit(OpCodes.Ldloc_0);  
  206.                         il.Emit(OpCodes.Ldfld, field);  
  207.                         il.Emit(OpCodes.Stfld, field);  
  208.                     }  
  209.                 }  
  210.                 for (type = type.BaseType; type != null && type != typeof(object); type = type.BaseType)  
  211.                 {  
  212.                     //只須要查找基類的私有成員,共有或受保護的在派生類中直接被複制過了。  
  213.                     fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList();  
  214.                     foreach (var field in fields)  
  215.                     {  
  216.                         if (!field.FieldType.IsValueType && field.FieldType != typeof(String))  
  217.                         {  
  218.                             //不符合條件的字段,直接忽略,避免報錯。  
  219.                             if ((field.FieldType.IsArray && (field.FieldType.GetArrayRank() > 1 || (!(tmptype = field.FieldType.GetElementType()).IsValueType && tmptype != typeof(String) && tmptype.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))) ||  
  220.                                 (!field.FieldType.IsArray && field.FieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) == null))  
  221.                                 break;  
  222.                             il.Emit(OpCodes.Ldloc_1);  
  223.                             il.Emit(OpCodes.Ldloc_0);  
  224.                             il.Emit(OpCodes.Ldfld, field);  
  225.                             il.Emit(OpCodes.Ldarg_1);  
  226.                             il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(field.FieldType), null);  
  227.                             il.Emit(OpCodes.Stfld, field);  
  228.                         }  
  229.                         else  
  230.                         {  
  231.                             il.Emit(OpCodes.Ldloc_1);  
  232.                             il.Emit(OpCodes.Ldloc_0);  
  233.                             il.Emit(OpCodes.Ldfld, field);  
  234.                             il.Emit(OpCodes.Stfld, field);  
  235.                         }  
  236.                     }  
  237.                 }  
  238.             }  
  239.             else  
  240.             {  
  241.                 Type arraytype = type.GetElementType();  
  242.                 var i = il.DeclareLocal(typeof(int));  
  243.                 var lb1 = il.DefineLabel();  
  244.                 var lb2 = il.DefineLabel();  
  245.                 il.Emit(OpCodes.Ldarg_0);  
  246.                 il.Emit(OpCodes.Castclass, type);  
  247.                 il.Emit(OpCodes.Dup);  
  248.                 il.Emit(OpCodes.Stloc_0);  
  249.                 il.Emit(OpCodes.Ldlen);  
  250.                 il.Emit(OpCodes.Dup);  
  251.                 il.Emit(OpCodes.Ldc_I4_1);  
  252.                 il.Emit(OpCodes.Sub);  
  253.                 il.Emit(OpCodes.Stloc, i);  
  254.                 il.Emit(OpCodes.Ldarg_2);  
  255.                 il.Emit(OpCodes.Castclass, type);  
  256.                 il.Emit(OpCodes.Dup);  
  257.                 il.Emit(OpCodes.Stloc_1);  
  258.                 il.Emit(OpCodes.Ldloc, i);  
  259.                 il.Emit(OpCodes.Br, lb1);  
  260.                 il.MarkLabel(lb2);  
  261.                 il.Emit(OpCodes.Dup);  
  262.                 il.Emit(OpCodes.Ldloc, i);  
  263.                 il.Emit(OpCodes.Ldloc_0);  
  264.                 il.Emit(OpCodes.Ldloc, i);  
  265.                 il.Emit(OpCodes.Ldelem, arraytype);  
  266.                 if (!arraytype.IsValueType && arraytype != typeof(String))  
  267.                 {  
  268.                     il.EmitCall(OpCodes.Call, typeof(ObjectCopy).GetMethod("CopyImpl", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(arraytype), null);  
  269.                 }  
  270.                 il.Emit(OpCodes.Stelem, arraytype);  
  271.                 il.Emit(OpCodes.Ldloc, i);  
  272.                 il.Emit(OpCodes.Ldc_I4_1);  
  273.                 il.Emit(OpCodes.Sub);  
  274.                 il.Emit(OpCodes.Dup);  
  275.                 il.Emit(OpCodes.Stloc, i);  
  276.                 il.MarkLabel(lb1);  
  277.                 il.Emit(OpCodes.Ldc_I4_0);  
  278.                 il.Emit(OpCodes.Clt);  
  279.                 il.Emit(OpCodes.Brfalse, lb2);  
  280.             }  
  281.             il.Emit(OpCodes.Ret);  
  282.   
  283.   
  284.             return (Action<object, Dictionary<Identity, object>, object>)dm.CreateDelegate(typeof(Action<object, Dictionary<Identity, object>, object>));  
  285.         }  
  286.   
  287.   
  288.         static T CopyImpl<T>(T source, Dictionary<Identity, object> objects) where T : class  
  289.         {  
  290.             //爲空則直接返回null  
  291.             if (source == null)  
  292.                 return null;  
  293.   
  294.   
  295.             Type type = source.GetType();  
  296.             Identity id = new Identity(source.GetHashCode(), type.TypeHandle);  
  297.             object result;  
  298.             //若是發現曾經複製過,用以前的,從而中止遞歸複製。  
  299.             if (!objects.TryGetValue(id, out result))  
  300.             {  
  301.                 //最後查找對象的複製方法,若是不存在,建立新的。  
  302.                 Func<object, Dictionary<Identity, object>, object> method;  
  303.                 if (!methods1.TryGetValue(type, out method))  
  304.                 {  
  305.                     method = CreateCloneMethod1(type, objects);  
  306.                     methods1.Add(type, method);  
  307.                 }  
  308.                 result = method(source, objects);  
  309.             }  
  310.             return (T)result;  
  311.         }  
  312.   
  313.   
  314.   
  315.   
  316.         /// <summary>  
  317.         /// 建立對象深度複製的副本  
  318.         /// </summary>  
  319.         public static T ToObjectCopy<T>(this T source) where T : class  
  320.         {  
  321.             Type type = source.GetType();  
  322.             Dictionary<Identity, object> objects = new Dictionary<Identity, object>();//存放內嵌引用類型的複製鏈,避免構成一個環。  
  323.             Func<object, Dictionary<Identity, object>, object> method;  
  324.             if (!methods1.TryGetValue(type, out method))  
  325.             {  
  326.                 method = CreateCloneMethod1(type, objects);  
  327.                 methods1.Add(type, method);  
  328.             }  
  329.             return (T)method(source, objects);  
  330.         }  
  331.   
  332.   
  333.   
  334.   
  335.         /// <summary>  
  336.         /// 將source對象的全部屬性複製到target對象中,深度複製  
  337.         /// </summary>  
  338.         public static void ObjectCopyTo<T>(this T source, T target) where T : class  
  339.         {  
  340.             if (target == null)  
  341.                 throw new Exception("將要複製的目標未初始化");  
  342.             Type type = source.GetType();  
  343.             if (type != target.GetType())  
  344.                 throw new Exception("要複製的對象類型不一樣,沒法複製");  
  345.             Dictionary<Identity, object> objects = new Dictionary<Identity, object>();//存放內嵌引用類型的複製鏈,避免構成一個環。  
  346.             objects.Add(new Identity(source.GetHashCode(), type.TypeHandle), source);  
  347.             Action<object, Dictionary<Identity, object>, object> method;  
  348.             if (!methods2.TryGetValue(type, out method))  
  349.             {  
  350.                 method = CreateCloneMethod2(type, objects);  
  351.                 methods2.Add(type, method);  
  352.             }  
  353.             method(source, objects, target);  
  354.         }  
  355.     }  
  356. }  


   花了很多精力研究的最高效的通用方法,目前能支持任何帶無參數的構造函數的類的深拷貝,一元數組的深拷貝,數組和類的循環嵌套深拷貝,雙向鏈表結構 的類型對象深拷貝,進行對象拷貝過程當中,未判斷任何附加特性,所以可序列化標誌對其無效,即便不可序列化的對象,也能夠進行深拷貝。 數據庫

  該方法是最基礎的方法,若是須要高級應用,能夠自定義特性(Attribute)進行忽略某些字段。 數組

  該方法最多用途就是在數據庫的實體對象的賦值上面,操做一個臨時對象(複製出來),若是中途放棄改動,則直接丟棄對象,不影響原先的對象,不然可將對象複製回去。 緩存

相關文章
相關標籤/搜索