Esempio n. 1
0
        internal static object GenerateClonerInternal(Type realType, bool asObject)
        {
            if (DeepClonerSafeTypes.IsTypeSafe(realType, null))
            {
                return(null);
            }

            return(GenerateProcessMethod(realType, asObject && realType.IsValueType()));
        }
Esempio n. 2
0
        internal static T[,] Clone2DimArrayInternal <T>(T[,] objFrom, T[,] objTo, DeepCloneState state, bool isDeep)
        {
            // not null from called method, but will check it anyway
            if (objFrom == null || objTo == null)
            {
                return(null);
            }
            var l1 = Math.Min(objFrom.GetLength(0), objTo.GetLength(0));
            var l2 = Math.Min(objFrom.GetLength(1), objTo.GetLength(1));

            state.AddKnownRef(objFrom, objTo);
            if ((!isDeep || DeepClonerSafeTypes.IsTypeSafe(typeof(T), null)) &&
                objFrom.GetLength(0) == objTo.GetLength(0) &&
                objFrom.GetLength(1) == objTo.GetLength(1))
            {
                Array.Copy(objFrom, objTo, objFrom.Length);
                return(objTo);
            }

            if (!isDeep)
            {
                for (var i = 0; i < l1; i++)
                {
                    for (var k = 0; k < l2; k++)
                    {
                        objTo[i, k] = objFrom[i, k];
                    }
                }
                return(objTo);
            }

            if (typeof(T).IsValueType())
            {
                var cloner = DeepClonerGenerator.GetClonerForValueType <T>();
                for (var i = 0; i < l1; i++)
                {
                    for (var k = 0; k < l2; k++)
                    {
                        objTo[i, k] = cloner(objFrom[i, k], state);
                    }
                }
            }
            else
            {
                for (var i = 0; i < l1; i++)
                {
                    for (var k = 0; k < l2; k++)
                    {
                        objTo[i, k] = (T)DeepClonerGenerator.CloneClassInternal(objFrom[i, k], state);
                    }
                }
            }

            return(objTo);
        }
Esempio n. 3
0
        private static object GenerateProcessArrayMethod(Type type, bool isDeep)
        {
            var elementType = type.GetElementType();
            var rank        = type.GetArrayRank();

            ParameterExpression from = Expression.Parameter(typeof(object));
            ParameterExpression to   = Expression.Parameter(typeof(object));
            var state = Expression.Parameter(typeof(DeepCloneState));

            var funcType = typeof(Func <, , ,>).MakeGenericType(typeof(object), typeof(object), typeof(DeepCloneState), typeof(object));

            if (rank == 1 && type == elementType.MakeArrayType())
            {
                if (!isDeep)
                {
                    var callS = Expression.Call(
                        typeof(ClonerToExprGenerator).GetPrivateStaticMethod("ShallowClone1DimArraySafeInternal")
                        .MakeGenericMethod(elementType), Expression.Convert(from, type), Expression.Convert(to, type));
                    return(Expression.Lambda(funcType, callS, from, to, state).Compile());
                }
                else
                {
                    var methodName = "Clone1DimArrayClassInternal";
                    if (DeepClonerSafeTypes.IsTypeSafe(elementType, null))
                    {
                        methodName = "Clone1DimArraySafeInternal";
                    }
                    else if (elementType.IsValueType())
                    {
                        methodName = "Clone1DimArrayStructInternal";
                    }
                    var methodInfo = typeof(ClonerToExprGenerator).GetPrivateStaticMethod(methodName).MakeGenericMethod(elementType);
                    var callS      = Expression.Call(methodInfo, Expression.Convert(from, type), Expression.Convert(to, type), state);
                    return(Expression.Lambda(funcType, callS, from, to, state).Compile());
                }
            }
            else
            {
                // multidim or not zero-based arrays
                var methodInfo = typeof(ClonerToExprGenerator).GetPrivateStaticMethod(
                    rank == 2 && type == elementType.MakeArrayType()
                                                ? "Clone2DimArrayInternal"
                                                : "CloneAbstractArrayInternal");
                var callS = Expression.Call(methodInfo, Expression.Convert(from, type), Expression.Convert(to, type), state, Expression.Constant(isDeep));
                return(Expression.Lambda(funcType, callS, from, to, state).Compile());
            }
        }
Esempio n. 4
0
        private static object GenerateProcessArrayMethod(Type type)
        {
            var elementType = type.GetElementType();
            var rank        = type.GetArrayRank();

            MethodInfo methodInfo;

            // multidim or not zero-based arrays
            if (rank != 1 || type != elementType.MakeArrayType())
            {
                if (rank == 2 && type == elementType.MakeArrayType())
                {
                    // small optimization for 2 dim arrays
                    methodInfo = typeof(DeepClonerGenerator).GetPrivateStaticMethod("Clone2DimArrayInternal").MakeGenericMethod(elementType);
                }
                else
                {
                    methodInfo = typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneAbstractArrayInternal");
                }
            }
            else
            {
                var methodName = "Clone1DimArrayClassInternal";
                if (DeepClonerSafeTypes.IsTypeSafe(elementType, null))
                {
                    methodName = "Clone1DimArraySafeInternal";
                }
                else if (elementType.IsValueType())
                {
                    methodName = "Clone1DimArrayStructInternal";
                }
                methodInfo = typeof(DeepClonerGenerator).GetPrivateStaticMethod(methodName).MakeGenericMethod(elementType);
            }

            ParameterExpression from = Expression.Parameter(typeof(object));
            var state = Expression.Parameter(typeof(DeepCloneState));
            var call  = Expression.Call(methodInfo, Expression.Convert(from, type), state);

            var funcType = typeof(Func <, ,>).MakeGenericType(typeof(object), typeof(DeepCloneState), typeof(object));

            return(Expression.Lambda(funcType, call, from, state).Compile());
        }
        // relatively frequent case. specially handled
        internal static T[,] Clone2DimArrayInternal <T>(T[,] obj, DeepCloneState state)
        {
            // not null from called method, but will check it anyway
            if (obj == null)
            {
                return(null);
            }
            var l1       = obj.GetLength(0);
            var l2       = obj.GetLength(1);
            var outArray = new T[l1, l2];

            state.AddKnownRef(obj, outArray);
            if (DeepClonerSafeTypes.IsTypeSafe(typeof(T), null))
            {
                Array.Copy(obj, outArray, obj.Length);
                return(outArray);
            }

            if (typeof(T).IsValueType())
            {
                var cloner = GetClonerForValueType <T>();
                for (var i = 0; i < l1; i++)
                {
                    for (var k = 0; k < l2; k++)
                    {
                        outArray[i, k] = cloner(obj[i, k], state);
                    }
                }
            }
            else
            {
                for (var i = 0; i < l1; i++)
                {
                    for (var k = 0; k < l2; k++)
                    {
                        outArray[i, k] = (T)CloneClassInternal(obj[i, k], state);
                    }
                }
            }

            return(outArray);
        }
Esempio n. 6
0
        private static object GenerateProcessMethod(Type type, bool unboxStruct)
        {
            if (type.IsArray)
            {
                return(GenerateProcessArrayMethod(type));
            }

            var methodType = unboxStruct || type.IsClass() ? typeof(object) : type;

            var expressionList = new List <Expression>();

            ParameterExpression from = Expression.Parameter(methodType);
            var fromLocal            = from;
            var toLocal = Expression.Variable(type);
            var state   = Expression.Parameter(typeof(DeepCloneState));

            if (!type.IsValueType())
            {
                var methodInfo = typeof(object).GetPrivateMethod("MemberwiseClone");

                // to = (T)from.MemberwiseClone()
                expressionList.Add(Expression.Assign(toLocal, Expression.Convert(Expression.Call(from, methodInfo), type)));

                fromLocal = Expression.Variable(type);
                // fromLocal = (T)from
                expressionList.Add(Expression.Assign(fromLocal, Expression.Convert(from, type)));

                // added from -> to binding to ensure reference loop handling
                // structs cannot loop here
                // state.AddKnownRef(from, to)
                expressionList.Add(Expression.Call(state, typeof(DeepCloneState).GetMethod("AddKnownRef"), from, toLocal));
            }
            else
            {
                if (unboxStruct)
                {
                    // toLocal = (T)from;
                    expressionList.Add(Expression.Assign(toLocal, Expression.Unbox(from, type)));
                    fromLocal = Expression.Variable(type);
                    // fromLocal = toLocal; // structs, it is ok to copy
                    expressionList.Add(Expression.Assign(fromLocal, toLocal));
                }
                else
                {
                    // toLocal = from
                    expressionList.Add(Expression.Assign(toLocal, from));
                }
            }

            List <FieldInfo> fi = new List <FieldInfo>();
            var tp = type;

            do
            {
#if !NETCORE
                // don't do anything with this dark magic!
                if (tp == typeof(ContextBoundObject))
                {
                    break;
                }
#else
                if (tp.Name == "ContextBoundObject")
                {
                    break;
                }
#endif

                fi.AddRange(tp.GetDeclaredFields());
                tp = tp.BaseType();
            }while (tp != null);

            foreach (var fieldInfo in fi)
            {
                if (!DeepClonerSafeTypes.IsTypeSafe(fieldInfo.FieldType, null))
                {
                    var methodInfo = fieldInfo.FieldType.IsValueType()
                                                                                ? typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneStructInternal")
                                     .MakeGenericMethod(fieldInfo.FieldType)
                                                                                : typeof(DeepClonerGenerator).GetPrivateStaticMethod("CloneClassInternal");

                    var get = Expression.Field(fromLocal, fieldInfo);

                    // toLocal.Field = Clone...Internal(fromLocal.Field)
                    var call = (Expression)Expression.Call(methodInfo, get, state);
                    if (!fieldInfo.FieldType.IsValueType())
                    {
                        call = Expression.Convert(call, fieldInfo.FieldType);
                    }

                    // should handle specially
                    // todo: think about optimization, but it rare case
                    if (fieldInfo.IsInitOnly)
                    {
                        // var setMethod = fieldInfo.GetType().GetMethod("SetValue", new[] { typeof(object), typeof(object) });
                        // expressionList.Add(Expression.Call(Expression.Constant(fieldInfo), setMethod, toLocal, call));
                        var 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));

            var funcType = typeof(Func <, ,>).MakeGenericType(methodType, typeof(DeepCloneState), methodType);

            var blockParams = new List <ParameterExpression>();
            if (from != fromLocal)
            {
                blockParams.Add(fromLocal);
            }
            blockParams.Add(toLocal);

            return(Expression.Lambda(funcType, Expression.Block(blockParams, expressionList), from, state).Compile());
        }