示例#1
0
        /// <summary>Clones a complex type using field-based value transfer</summary>
        /// <param name="original">Original instance that will be cloned</param>
        /// <returns>A clone of the original instance</returns>
        private static object shallowCloneComplexFieldBased(object original)
        {
            Type originalType = original.GetType();

#if (XBOX360 || WINDOWS_PHONE)
            object clone = Activator.CreateInstance(originalType);
#else
            object clone = FormatterServices.GetUninitializedObject(originalType);
#endif

            FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
                originalType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                );
            for (int index = 0; index < fieldInfos.Length; ++index)
            {
                FieldInfo fieldInfo     = fieldInfos[index];
                object    originalValue = fieldInfo.GetValue(original);
                if (originalValue != null)
                {
                    // Everything's just directly assigned in a shallow clone
                    fieldInfo.SetValue(clone, originalValue);
                }
            }

            return(clone);
        }
        /// <summary>Generates state transfer expressions to copy a complex type</summary>
        /// <param name="clonedType">Complex type that will be cloned</param>
        /// <param name="original">Variable expression for the original instance</param>
        /// <param name="clone">Variable expression for the cloned instance</param>
        /// <param name="variables">Receives variables used by the transfer expressions</param>
        /// <param name="transferExpressions">Receives the generated transfer expressions</param>
        private static void generateFieldBasedComplexTypeTransferExpressions(
            Type clonedType,     // Actual, concrete type (not declared type)
            Expression original, // Expected to be an object
            Expression clone,    // As actual, concrete type
            IList <ParameterExpression> variables,
            ICollection <Expression> transferExpressions
            )
        {
            // Enumerate all of the type's fields and generate transfer expressions for each
            FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
                clonedType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                );
            for (int index = 0; index < fieldInfos.Length; ++index)
            {
                FieldInfo fieldInfo = fieldInfos[index];
                Type      fieldType = fieldInfo.FieldType;

                if (fieldType.IsPrimitive || (fieldType == typeof(string)))
                {
                    // Primitive types and strings can be transferred by simple assignment
                    transferExpressions.Add(
                        Expression.Assign(
                            Expression.Field(clone, fieldInfo),
                            Expression.Field(original, fieldInfo)
                            )
                        );
                }
                else if (fieldType.IsValueType)
                {
                    // A nested value type is part of the parent and will have its fields directly
                    // assigned without boxing, new instance creation or anything like that.
                    generateFieldBasedComplexTypeTransferExpressions(
                        fieldType,
                        Expression.Field(original, fieldInfo),
                        Expression.Field(clone, fieldInfo),
                        variables,
                        transferExpressions
                        );
                }
                else
                {
                    generateFieldBasedReferenceTypeTransferExpressions(
                        original, clone, transferExpressions, fieldInfo, fieldType
                        );
                }
            }
        }
示例#3
0
        /// <summary>Clones a complex type using field-based value transfer</summary>
        /// <param name="original">Original instance that will be cloned</param>
        /// <returns>A clone of the original instance</returns>
        private static object deepCloneComplexFieldBased(object original)
        {
            Type originalType = original.GetType();

#if (XBOX360 || WINDOWS_PHONE)
            object clone = Activator.CreateInstance(originalType);
#else
            object clone = FormatterServices.GetUninitializedObject(originalType);
#endif

            FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
                originalType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                );
            for (int index = 0; index < fieldInfos.Length; ++index)
            {
                FieldInfo fieldInfo     = fieldInfos[index];
                Type      fieldType     = fieldInfo.FieldType;
                object    originalValue = fieldInfo.GetValue(original);
                if (originalValue != null)
                {
                    // Primitive types can be assigned directly
                    if (fieldType.IsPrimitive || (fieldType == typeof(string)))
                    {
                        fieldInfo.SetValue(clone, originalValue);
                    }
                    else if (fieldType.IsArray)
                    {
                        // Arrays need to be cloned element-by-element
                        fieldInfo.SetValue(
                            clone,
                            deepCloneArrayFieldBased((Array)originalValue, fieldType.GetElementType())
                            );
                    }
                    else
                    {
                        // Complex types need to be cloned member-by-member
                        fieldInfo.SetValue(clone, deepCloneSingleFieldBased(originalValue));
                    }
                }
            }

            return(clone);
        }
        /// <summary>Compiles a method that creates a shallow clone of an object</summary>
        /// <param name="clonedType">Type for which a clone method will be created</param>
        /// <returns>A method that clones an object of the provided type</returns>
        private static Func <object, object> createShallowFieldBasedCloner(Type clonedType)
        {
            ParameterExpression original = Expression.Parameter(typeof(object), "original");

            var transferExpressions = new List <Expression>();
            var variables           = new List <ParameterExpression>();

            if (clonedType.IsPrimitive || clonedType.IsValueType || (clonedType == typeof(string)))
            {
                // Primitives and strings are copied on direct assignment
                transferExpressions.Add(original);
            }
            else if (clonedType.IsArray)
            {
                transferExpressions.Add(
                    generateFieldBasedPrimitiveArrayTransferExpressions(
                        clonedType, original, variables, transferExpressions
                        )
                    );
            }
            else
            {
                // We need a variable to hold the clone because due to the assignments it
                // won't be last in the block when we're finished
                ParameterExpression clone = Expression.Variable(clonedType);
                variables.Add(clone);

                // To access the fields of the original type, we need it to be of the actual
                // type instead of an object, so perform a downcast
                ParameterExpression typedOriginal = Expression.Variable(clonedType);
                variables.Add(typedOriginal);
                transferExpressions.Add(
                    Expression.Assign(typedOriginal, Expression.Convert(original, clonedType))
                    );

                // Give it a new instance of the type being cloned
                MethodInfo getUninitializedObjectMethodInfo = typeof(FormatterServices).GetMethod(
                    "GetUninitializedObject", BindingFlags.Static | BindingFlags.Public
                    );
                transferExpressions.Add(
                    Expression.Assign(
                        clone,
                        Expression.Convert(
                            Expression.Call(
                                getUninitializedObjectMethodInfo, Expression.Constant(clonedType)
                                ),
                            clonedType
                            )
                        )
                    );

                // Enumerate all of the type's fields and generate transfer expressions for each
                FieldInfo[] fieldInfos = ClonerHelpers.GetFieldInfosIncludingBaseClasses(
                    clonedType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                    );
                for (int index = 0; index < fieldInfos.Length; ++index)
                {
                    FieldInfo fieldInfo = fieldInfos[index];

                    transferExpressions.Add(
                        Expression.Assign(
                            Expression.Field(clone, fieldInfo),
                            Expression.Field(typedOriginal, fieldInfo)
                            )
                        );
                }

                // Make sure the clone is the last thing in the block to set the return value
                transferExpressions.Add(clone);
            }

            // Turn all transfer expressions into a single block if necessary
            Expression resultExpression;

            if ((transferExpressions.Count == 1) && (variables.Count == 0))
            {
                resultExpression = transferExpressions[0];
            }
            else
            {
                resultExpression = Expression.Block(variables, transferExpressions);
            }

            // Value types require manual boxing
            if (clonedType.IsValueType)
            {
                resultExpression = Expression.Convert(resultExpression, typeof(object));
            }

            return(Expression.Lambda <Func <object, object> >(resultExpression, original).Compile());
        }