public static T CloneDeep <T>(T source) { Delegate @delegate = (Delegate)null; if (!CloneUtility.cachedILDeep.TryGetValue(typeof(T), out @delegate)) { DynamicMethod dynamicMethod = new DynamicMethod("DoClone", typeof(T), new Type[1] { typeof(T) }, Assembly.GetExecutingAssembly().ManifestModule, 1 != 0); ConstructorInfo constructor = source.GetType().GetConstructor(new Type[0]); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); ilGenerator.DeclareLocal(typeof(T)); ilGenerator.Emit(OpCodes.Newobj, constructor); ilGenerator.Emit(OpCodes.Stloc_0); foreach (FieldInfo field in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { if (field.FieldType.IsValueType || field.FieldType == typeof(string)) { CloneUtility.CopyValueType(ilGenerator, field); } else if (field.FieldType.IsClass) { CloneUtility.CopyReferenceType(ilGenerator, field); } } ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); @delegate = dynamicMethod.CreateDelegate(typeof(Func <T, T>)); CloneUtility.cachedILDeep.Add(typeof(T), @delegate); } return(((Func <T, T>)@delegate)(source)); }
private static void CopyReferenceType(ILGenerator generator, FieldInfo field) { LocalBuilder localBuilder = generator.DeclareLocal(field.FieldType); if (field.FieldType.GetInterface("IEnumerable") != (Type)null) { if (!field.FieldType.IsGenericType) { return; } Type type = Type.GetType("System.Collections.Generic.IEnumerable`1[" + field.FieldType.GetGenericArguments()[0].FullName + "]"); ConstructorInfo constructor = field.FieldType.GetConstructor(new Type[1] { type }); if (!(constructor != (ConstructorInfo)null)) { return; } generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, field); generator.Emit(OpCodes.Newobj, constructor); generator.Emit(OpCodes.Stloc, localBuilder); CloneUtility.PlaceNewTempObjInClone(generator, field, localBuilder); } else { CloneUtility.CreateNewTempObject(generator, field.FieldType, localBuilder); CloneUtility.PlaceNewTempObjInClone(generator, field, localBuilder); foreach (FieldInfo field1 in field.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { if (field1.FieldType.IsValueType || field1.FieldType == typeof(string)) { CloneUtility.CopyValueTypeTemp(generator, field, field1); } else if (field1.FieldType.IsClass) { CloneUtility.CopyReferenceType(generator, field1); } } } }