private static object GenerateProcessArrayMethod(Type type) { Type elementType = type.GetElementType(); int rank = type.GetArrayRank(); MethodInfo methodInfo; if (rank != 1 || type != elementType.MakeArrayType()) { methodInfo = ((rank != 2 || !(type == elementType.MakeArrayType())) ? typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneAbstractArrayInternal") : typeof(DeepClonerGenerator).GetPrivateStaticMethod("Clone2DimArrayInternal").MakeGenericMethod(elementType)); } else { string methodName = "Clone1DimArrayClassInternal"; if (DeepClonerSafeTypes.CanReturnSameObject(elementType)) { methodName = "Clone1DimArraySafeInternal"; } else if (elementType.IsValueType()) { methodName = "Clone1DimArrayStructInternal"; } methodInfo = typeof(DeepClonerGenerator).GetPrivateStaticMethod(methodName).MakeGenericMethod(elementType); } ParameterExpression from = Expression.Parameter(typeof(object)); ParameterExpression state = Expression.Parameter(typeof(DeepCloneState)); MethodCallExpression call = Expression.Call(methodInfo, Expression.Convert(from, type), state); return(Expression.Lambda(typeof(Func <, , >).MakeGenericType(typeof(object), typeof(DeepCloneState), typeof(object)), call, from, state).Compile()); }
private static object GenerateProcessArrayMethod(Type type, bool isDeep) { Type elementType = type.GetElementType(); int rank = type.GetArrayRank(); ParameterExpression from = Expression.Parameter(typeof(object)); ParameterExpression to = Expression.Parameter(typeof(object)); ParameterExpression state = Expression.Parameter(typeof(DeepCloneState)); Type funcType = typeof(Func <, , , >).MakeGenericType(typeof(object), typeof(object), typeof(DeepCloneState), typeof(object)); if (rank == 1 && type == elementType.MakeArrayType()) { if (!isDeep) { MethodCallExpression callS3 = Expression.Call(typeof(ClonerToExprGenerator).GetPrivateStaticMethod("ShallowClone1DimArraySafeInternal").MakeGenericMethod(elementType), Expression.Convert(from, type), Expression.Convert(to, type)); return(Expression.Lambda(funcType, callS3, from, to, state).Compile()); } string methodName = "Clone1DimArrayClassInternal"; if (DeepClonerSafeTypes.CanReturnSameObject(elementType)) { methodName = "Clone1DimArraySafeInternal"; } else if (elementType.IsValueType()) { methodName = "Clone1DimArrayStructInternal"; } MethodCallExpression callS2 = Expression.Call(typeof(ClonerToExprGenerator).GetPrivateStaticMethod(methodName).MakeGenericMethod(elementType), Expression.Convert(from, type), Expression.Convert(to, type), state); return(Expression.Lambda(funcType, callS2, from, to, state).Compile()); } MethodCallExpression callS = Expression.Call(typeof(ClonerToExprGenerator).GetPrivateStaticMethod((rank == 2 && type == elementType.MakeArrayType()) ? "Clone2DimArrayInternal" : "CloneAbstractArrayInternal"), Expression.Convert(from, type), Expression.Convert(to, type), state, Expression.Constant(isDeep)); return(Expression.Lambda(funcType, callS, from, to, state).Compile()); }
private static object GenerateCloner(Type t, bool asObject) { if (DeepClonerSafeTypes.CanReturnSameObject(t) && asObject && !t.IsValueType()) { return(null); } if (ShallowObjectCloner.IsSafeVariant()) { return(DeepClonerExprGenerator.GenerateClonerInternal(t, asObject)); } return(DeepClonerMsilGenerator.GenerateClonerInternal(t, asObject)); }
internal static T[,] Clone2DimArrayInternal <T>(T[,] objFrom, T[,] objTo, DeepCloneState state, bool isDeep) { if (objFrom == null || objTo == null) { return(null); } int l3 = Math.Min(objFrom.GetLength(0), objTo.GetLength(0)); int l2 = Math.Min(objFrom.GetLength(1), objTo.GetLength(1)); state.AddKnownRef(objFrom, objTo); if ((!isDeep || DeepClonerSafeTypes.CanReturnSameObject(typeof(T))) && objFrom.GetLength(0) == objTo.GetLength(0) && objFrom.GetLength(1) == objTo.GetLength(1)) { Array.Copy(objFrom, objTo, objFrom.Length); return(objTo); } if (!isDeep) { for (int n = 0; n < l3; n++) { for (int m = 0; m < l2; m++) { objTo[n, m] = objFrom[n, m]; } } return(objTo); } if (typeof(T).IsValueType()) { Func <T, DeepCloneState, T> cloner = DeepClonerGenerator.GetClonerForValueType <T>(); for (int l = 0; l < l3; l++) { for (int k = 0; k < l2; k++) { objTo[l, k] = cloner(objFrom[l, k], state); } } } else { for (int j = 0; j < l3; j++) { for (int i = 0; i < l2; i++) { objTo[j, i] = (T)DeepClonerGenerator.CloneClassInternal(objFrom[j, i], state); } } } return(objTo); }
public static T CloneObject <T>(T obj) { if (obj is ValueType) { Type type = obj.GetType(); if (typeof(T) == type) { if (DeepClonerSafeTypes.CanReturnSameObject(type)) { return(obj); } return(CloneStructInternal(obj, new DeepCloneState())); } } return((T)CloneClassRoot(obj)); }
public static T CloneObject <T>(T obj) { if (obj is ValueType) { if (typeof(T) == obj.GetType()) { return(obj); } return((T)ShallowObjectCloner.CloneObject(obj)); } if (obj == null) { return((T)(object)null); } if (DeepClonerSafeTypes.CanReturnSameObject(obj.GetType())) { return(obj); } return((T)ShallowObjectCloner.CloneObject(obj)); }
internal static T[,] Clone2DimArrayInternal <T>(T[,] obj, DeepCloneState state) { if (obj == null) { return(null); } int l3 = obj.GetLength(0); int l2 = obj.GetLength(1); T[,] outArray = new T[l3, l2]; state.AddKnownRef(obj, outArray); if (DeepClonerSafeTypes.CanReturnSameObject(typeof(T))) { Array.Copy(obj, outArray, obj.Length); return(outArray); } if (typeof(T).IsValueType()) { Func <T, DeepCloneState, T> cloner = GetClonerForValueType <T>(); for (int l = 0; l < l3; l++) { for (int k = 0; k < l2; k++) { outArray[l, k] = cloner(obj[l, k], state); } } } else { for (int j = 0; j < l3; j++) { for (int i = 0; i < l2; i++) { outArray[j, i] = (T)CloneClassInternal(obj[j, i], state); } } } return(outArray); }
private static void GenerateProcessMethod(ILGenerator il, Type type, bool unboxStruct) { if (type.IsArray) { GenerateProcessArrayMethod(il, type); return; } if (type.FullName != null && type.FullName.StartsWith("System.Tuple`")) { Type[] genericArguments = type.GenericArguments(); if (genericArguments.Length < 10 && genericArguments.All(DeepClonerSafeTypes.CanReturnSameObject)) { GenerateProcessTupleMethod(il, type); return; } } LocalBuilder typeLocal = il.DeclareLocal(type); LocalBuilder structLoc = null; bool isGoodConstructor = false; if (!type.IsValueType) { ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); isGoodConstructor = DeepClonerMsilHelper.IsConstructorDoNothing(type, constructor); if (isGoodConstructor) { il.Emit(OpCodes.Newobj, constructor); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic)); } il.Emit(OpCodes.Stloc, typeLocal); } else if (unboxStruct) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Unbox_Any, type); structLoc = il.DeclareLocal(type); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, structLoc); il.Emit(OpCodes.Stloc, typeLocal); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Stloc, typeLocal); } if (type.IsClass) { il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc, typeLocal); il.Emit(OpCodes.Call, typeof(DeepCloneState).GetMethod("AddKnownRef")); } List <FieldInfo> fi = new List <FieldInfo>(); Type tp = type; while (!(tp == typeof(ContextBoundObject))) { fi.AddRange(tp.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)); tp = tp.BaseType; if (!(tp != null)) { break; } } foreach (FieldInfo fieldInfo in fi) { if (DeepClonerSafeTypes.CanReturnSameObject(fieldInfo.FieldType)) { if (isGoodConstructor) { il.Emit(type.IsClass ? OpCodes.Ldloc : OpCodes.Ldloca_S, typeLocal); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, fieldInfo); il.Emit(OpCodes.Stfld, fieldInfo); } continue; } il.Emit(type.IsClass ? OpCodes.Ldloc : OpCodes.Ldloca_S, typeLocal); if (structLoc == null) { il.Emit(OpCodes.Ldarg_0); } else { il.Emit(OpCodes.Ldloc, structLoc); } il.Emit(OpCodes.Ldfld, fieldInfo); il.Emit(OpCodes.Ldarg_1); MethodInfo methodInfo = (fieldInfo.FieldType.IsValueType ? typeof(DeepClonerGenerator).GetMethod("CloneStructInternal", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(fieldInfo.FieldType) : typeof(DeepClonerGenerator).GetMethod("CloneClassInternal", BindingFlags.Static | BindingFlags.NonPublic)); il.Emit(OpCodes.Call, methodInfo); il.Emit(OpCodes.Stfld, fieldInfo); } il.Emit(OpCodes.Ldloc, typeLocal); if (unboxStruct) { il.Emit(OpCodes.Box, type); } il.Emit(OpCodes.Ret); }
private static void GenerateProcessArrayMethod(ILGenerator il, Type type) { Type elementType = type.GetElementType(); int rank = type.GetArrayRank(); if (rank != 1 || type != elementType.MakeArrayType()) { MethodInfo methodInfo = ((rank != 2 || !(type == elementType.MakeArrayType())) ? typeof(DeepClonerGenerator).GetMethod("CloneAbstractArrayInternal", BindingFlags.Static | BindingFlags.NonPublic) : typeof(DeepClonerGenerator).GetMethod("Clone2DimArrayInternal", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(elementType)); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, methodInfo); il.Emit(OpCodes.Ret); return; } LocalBuilder typeLocal = il.DeclareLocal(type); LocalBuilder lenLocal = il.DeclareLocal(typeof(int)); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, type.GetProperty("Length").GetGetMethod()); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Stloc, lenLocal); il.Emit(OpCodes.Newarr, elementType); il.Emit(OpCodes.Stloc, typeLocal); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc, typeLocal); il.Emit(OpCodes.Call, typeof(DeepCloneState).GetMethod("AddKnownRef")); if (DeepClonerSafeTypes.CanReturnSameObject(elementType)) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc, typeLocal); il.Emit(OpCodes.Ldloc, lenLocal); il.Emit(OpCodes.Call, typeof(Array).GetMethod("Copy", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Array), typeof(Array), typeof(int) }, null)); } else { MethodInfo methodInfo2 = (elementType.IsValueType ? typeof(DeepClonerGenerator).GetMethod("CloneStructInternal", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(elementType) : typeof(DeepClonerGenerator).GetMethod("CloneClassInternal", BindingFlags.Static | BindingFlags.NonPublic)); LocalBuilder clonerLocal = null; if (type.IsValueType) { Type funcType = typeof(Func <, , >).MakeGenericType(elementType, typeof(DeepCloneState), elementType); methodInfo2 = funcType.GetMethod("Invoke"); clonerLocal = il.DeclareLocal(funcType); il.Emit(OpCodes.Call, typeof(DeepClonerGenerator).GetMethod("GetClonerForValueType", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(elementType)); il.Emit(OpCodes.Stloc, clonerLocal); } Label endLoopLabel = il.DefineLabel(); Label startLoopLabel = il.DefineLabel(); LocalBuilder iLocal = il.DeclareLocal(typeof(int)); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc, iLocal); il.MarkLabel(startLoopLabel); il.Emit(OpCodes.Ldloc, iLocal); il.Emit(OpCodes.Ldloc, lenLocal); il.Emit(OpCodes.Bge_S, endLoopLabel); il.Emit(OpCodes.Ldloc, typeLocal); il.Emit(OpCodes.Ldloc, iLocal); if (clonerLocal != null) { il.Emit(OpCodes.Ldloc, clonerLocal); } il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloc, iLocal); il.Emit(OpCodes.Ldelem, elementType); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Call, methodInfo2); il.Emit(OpCodes.Stelem, elementType); il.Emit(OpCodes.Ldloc, iLocal); il.Emit(OpCodes.Ldc_I4_1); il.Emit(OpCodes.Add); il.Emit(OpCodes.Stloc, iLocal); il.Emit(OpCodes.Br_S, startLoopLabel); il.MarkLabel(endLoopLabel); } il.Emit(OpCodes.Ldloc, typeLocal); il.Emit(OpCodes.Ret); }
private static object GenerateProcessMethod(Type type, bool unboxStruct) { if (type.IsArray) { return(GenerateProcessArrayMethod(type)); } if (type.FullName != null && type.FullName.StartsWith("System.Tuple`")) { Type[] genericArguments = type.GenericArguments(); if (genericArguments.Length < 10 && genericArguments.All(DeepClonerSafeTypes.CanReturnSameObject)) { return(GenerateProcessTupleMethod(type)); } } Type methodType = ((unboxStruct || type.IsClass()) ? typeof(object) : type); List <Expression> expressionList = new List <Expression>(); ParameterExpression from = Expression.Parameter(methodType); ParameterExpression fromLocal = from; ParameterExpression toLocal = Expression.Variable(type); ParameterExpression state = Expression.Parameter(typeof(DeepCloneState)); if (!type.IsValueType()) { MethodInfo methodInfo = typeof(object).GetPrivateMethod("MemberwiseClone"); expressionList.Add(Expression.Assign(toLocal, Expression.Convert(Expression.Call(from, methodInfo), type))); fromLocal = Expression.Variable(type); expressionList.Add(Expression.Assign(fromLocal, Expression.Convert(from, type))); expressionList.Add(Expression.Call(state, typeof(DeepCloneState).GetMethod("AddKnownRef"), from, toLocal)); } else if (unboxStruct) { expressionList.Add(Expression.Assign(toLocal, Expression.Unbox(from, type))); fromLocal = Expression.Variable(type); expressionList.Add(Expression.Assign(fromLocal, toLocal)); } else { expressionList.Add(Expression.Assign(toLocal, from)); } List <FieldInfo> fi = new List <FieldInfo>(); Type tp = type; while (!(tp == typeof(ContextBoundObject))) { fi.AddRange(tp.GetDeclaredFields()); tp = tp.BaseType(); if (!(tp != null)) { break; } } foreach (FieldInfo fieldInfo in fi) { if (!DeepClonerSafeTypes.CanReturnSameObject(fieldInfo.FieldType)) { MethodInfo method = (fieldInfo.FieldType.IsValueType() ? typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneStructInternal").MakeGenericMethod(fieldInfo.FieldType) : typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneClassInternal")); MemberExpression get = Expression.Field(fromLocal, fieldInfo); Expression call = Expression.Call(method, get, state); if (!fieldInfo.FieldType.IsValueType()) { call = Expression.Convert(call, fieldInfo.FieldType); } if (_readonlyFields.GetOrAdd(fieldInfo, (FieldInfo f) => f.IsInitOnly)) { MethodInfo setMethod = typeof(DeepClonerExprGenerator).GetPrivateStaticMethod("ForceSetField"); expressionList.Add(Expression.Call(setMethod, Expression.Constant(fieldInfo), Expression.Convert(toLocal, typeof(object)), Expression.Convert(call, typeof(object)))); } else { expressionList.Add(Expression.Assign(Expression.Field(toLocal, fieldInfo), call)); } } } expressionList.Add(Expression.Convert(toLocal, methodType)); Type delegateType = typeof(Func <, , >).MakeGenericType(methodType, typeof(DeepCloneState), methodType); List <ParameterExpression> blockParams = new List <ParameterExpression>(); if (from != fromLocal) { blockParams.Add(fromLocal); } blockParams.Add(toLocal); return(Expression.Lambda(delegateType, Expression.Block(blockParams, expressionList), from, state).Compile()); }
private static object GenerateProcessMethod(Type type, bool isDeepClone) { if (type.IsArray) { return(GenerateProcessArrayMethod(type, isDeepClone)); } Type methodType = typeof(object); List <Expression> expressionList = new List <Expression>(); ParameterExpression from = Expression.Parameter(methodType); ParameterExpression fromLocal2 = from; ParameterExpression to = Expression.Parameter(methodType); ParameterExpression toLocal2 = to; ParameterExpression state = Expression.Parameter(typeof(DeepCloneState)); fromLocal2 = Expression.Variable(type); toLocal2 = Expression.Variable(type); expressionList.Add(Expression.Assign(fromLocal2, Expression.Convert(from, type))); expressionList.Add(Expression.Assign(toLocal2, Expression.Convert(to, type))); if (isDeepClone) { expressionList.Add(Expression.Call(state, typeof(DeepCloneState).GetMethod("AddKnownRef"), from, to)); } List <FieldInfo> fi = new List <FieldInfo>(); Type tp = type; while (!(tp == typeof(ContextBoundObject))) { fi.AddRange(tp.GetDeclaredFields()); tp = tp.BaseType(); if (!(tp != null)) { break; } } foreach (FieldInfo fieldInfo in fi) { if (isDeepClone && !DeepClonerSafeTypes.CanReturnSameObject(fieldInfo.FieldType)) { MethodInfo method = fieldInfo.FieldType.IsValueType() ? typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneStructInternal").MakeGenericMethod(fieldInfo.FieldType) : typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneClassInternal"); MemberExpression get = Expression.Field(fromLocal2, fieldInfo); Expression call = Expression.Call(method, get, state); if (!fieldInfo.FieldType.IsValueType()) { call = Expression.Convert(call, fieldInfo.FieldType); } if (fieldInfo.IsInitOnly) { MethodInfo setMethod = typeof(DeepClonerExprGenerator).GetPrivateStaticMethod("ForceSetField"); expressionList.Add(Expression.Call(setMethod, Expression.Constant(fieldInfo), Expression.Convert(toLocal2, typeof(object)), Expression.Convert(call, typeof(object)))); } else { expressionList.Add(Expression.Assign(Expression.Field(toLocal2, fieldInfo), call)); } } else { expressionList.Add(Expression.Assign(Expression.Field(toLocal2, fieldInfo), Expression.Field(fromLocal2, fieldInfo))); } } expressionList.Add(Expression.Convert(toLocal2, methodType)); Type delegateType = typeof(Func <, , , >).MakeGenericType(methodType, methodType, typeof(DeepCloneState), methodType); List <ParameterExpression> blockParams = new List <ParameterExpression>(); if (from != fromLocal2) { blockParams.Add(fromLocal2); } if (to != toLocal2) { blockParams.Add(toLocal2); } return(Expression.Lambda(delegateType, Expression.Block(blockParams, expressionList), from, to, state).Compile()); }