예제 #1
0
        static object Clone(object instance, VisitedGraph visited, object clone)
        {
            if (visited.ContainsKey(instance))
            {
                return(visited[instance]);
            }

            visited.Add(instance, clone);

            Type type = instance.GetType();

            while (type != null)
            {
                var ta = TypeAccessor.GetAccessor(type);
                foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
                {
                    object value      = ta.GetField(field.Name, instance);
                    object cloneValue = visited.ContainsKey(value) ? visited[value] : Clone(value, visited);
                    ta.SetField(field.Name, clone, cloneValue);
                }

                type = type.BaseType;
            }
            return(clone);
        }
예제 #2
0
        /// <summary>
        /// Creates a deep copy of an object using the supplied dictionary of visited objects as 
        /// a source of objects already encountered in the copy traversal. The dictionary of visited 
        /// objects is used for holding objects that have already been copied, to avoid erroneous 
        /// duplication of parts of the object graph.
        /// </summary>
        /// <param name="instance">The object to be copied.</param>
        /// <param name="visited">The graph of objects visited so far.</param>
        /// <returns></returns>
        private static object Clone(this object instance, VisitedGraph visited)
        {
            if (instance == null)
                return null;

            Type instanceType = instance.GetType();

            if (instanceType.IsValueType || instanceType == typeof(string))
                return instance; // Value types and strings are immutable
            else if (instanceType.IsArray)
            {
                int length = ((Array)instance).Length;
                Array copied = (Array)Activator.CreateInstance(instanceType, length);
                visited.Add(instance, copied);
                for (int i = 0; i < length; ++i)
                    copied.SetValue(((Array)instance).GetValue(i).Clone(visited), i);
                return copied;
            }
            else
                return Clone(instance, visited, InstanceCreator.GetInstance(instanceType));
        }
예제 #3
0
        static object Clone(object instance, VisitedGraph visited)
        {
            if (instance == null)
            {
                return(null);
            }

            Type instanceType = instance.GetType();

            if (instanceType.IsPointer || instanceType == typeof(Pointer) || instanceType.IsPrimitive || instanceType == typeof(string))
            {
                return(instance); // Pointers, primitive types and strings are considered immutable
            }
            if (instanceType.GetInterface(CloneableInterface) != null)
            {
                return(((ICloneable)instance).Clone());
            }

            if (typeof(Type).IsAssignableFrom(instanceType) || typeof(MemberInfo).IsAssignableFrom(instanceType) || typeof(ParameterInfo).IsAssignableFrom(instanceType))
            {
                return(instance);
            }

            if (instanceType.IsArray)
            {
                var   array  = (Array)instance;
                int   length = array.Length;
                Array copied = (Array)Activator.CreateInstance(instanceType, length);
                visited.Add(instance, copied);
                for (int i = 0; i < length; ++i)
                {
                    var clone = Clone(array.GetValue(i), visited);
                    copied.SetValue(clone, i);
                }
                return(copied);
            }

            return(Clone(instance, visited, CreateInstance(instanceType)));
        }
예제 #4
0
        private static object Clone(this object instance, VisitedGraph visited, object copy)
        {
            visited.Add(instance, copy);

            var type = instance.GetType();

            foreach (var field in GetTypeCopyableFieldList(type))
            {
                object value = field.Getter(instance);
                object cloned;
                if (value == null)
                    cloned = null;
                else if (!visited.TryGetValue(value, out cloned))
                    cloned = value.Clone(visited);
                field.Setter(copy, cloned);
            }
            return copy;
        }
        /// <summary>
        /// Creates a deep copy of an object using the supplied dictionary of visited objects as
        /// a source of objects already encountered in the copy traversal. The dictionary of visited
        /// objects is used for holding objects that have already been copied, to avoid erroneous
        /// duplication of parts of the object graph.
        /// </summary>
        /// <param name="instance">The object to be copied.</param>
        /// <param name="visited">The graph of objects visited so far.</param>
        /// <param name="copy">The object to copy to.</param>
        /// <param name="expectedType">The type that should be found.</param>
        /// <param name="overrideSettings">Settings to override the copy logic.</param>
        /// <typeparam name="T">The type of the instance given.</typeparam>
        /// <returns>The copied object.</returns>
        private static T Clone <T>(this T instance, VisitedGraph visited, T copy, Type expectedType, IList <ICopyOverrideSettings> overrideSettings = null)
        {
            if (ShouldUseVisitedGraph(overrideSettings))
            {
                if (visited.ContainsKey(instance))
                {
                    return((T)visited[instance]);
                }
                else
                {
                    visited.Add(instance, copy);
                }
            }

            Type   type = instance.GetType();
            string instanceTypeNameString = type.FullName;
            bool   shouldSkip             = CheckIfShouldSkip(overrideSettings, type.FullName, false);

            if (shouldSkip)
            {
                return(default(T));
            }

            BindingFlags flags = overrideSettings?.Any(s => s.IncludeNonPublic) ?? true
                                ? BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                                : BindingFlags.Public | BindingFlags.Instance;

            while (type != null)
            {
                List <ICopyOverrideSettings> currentSettings = overrideSettings?.Where(s => s.ContainingClassType.IsAssignableFrom(type))
                                                               .ToList() ?? new List <ICopyOverrideSettings>();

                foreach (FieldInfo field in type.GetFields(flags))
                {
                    shouldSkip = false;
                    shouldSkip = CheckIfShouldSkip(overrideSettings, field?.FieldType?.FullName, shouldSkip);

                    if (shouldSkip || ShouldSkipDotNet(type, field.FieldType, field.Name))
                    {
                        continue;
                    }

                    object value = field.GetValue(instance);
                    ICopyOverrideSettings currentOverride = currentSettings.SingleOrDefault(s => s.FieldValueOverrideType.IsAssignableFrom(field.FieldType) &&
                                                                                            s.ContainingClassType.IsAssignableFrom(type) &&
                                                                                            s.AffectedFieldName == field.Name);
                    try
                    {
                        if (currentOverride != null)
                        {
                            if (!currentOverride.ShouldSkipOverrideInsteadOfSet)
                            {
                                var settableValue = currentOverride.UseFieldValueOverrideFunction
                                                                        ? currentOverride.FieldValueOverrideFunction(instance)
                                                                        : currentOverride.FieldValueOverride;
                                field.SetValue(copy, settableValue);
                                if (currentOverride.OnlyOverrideFirst)
                                {
                                    overrideSettings.Remove(overrideSettings.Single(s => s.AffectedFieldName == s.AffectedFieldName &&
                                                                                    s.ContainingClassType == s.ContainingClassType && s.FieldValueOverride == s.FieldValueOverride &&
                                                                                    s.FieldValueOverrideType == s.FieldValueOverrideType && s.OnlyOverrideFirst == s.OnlyOverrideFirst));
                                }
                            }
                        }
                        else if (ShouldUseVisitedGraph(overrideSettings) && visited.ContainsKey(value))
                        {
                            var settableValue = visited[value];
                            field.SetValue(copy, settableValue);
                        }
                        else
                        {
                            var settableValue = value.Clone(visited, field.FieldType, overrideSettings);
                            field.SetValue(copy, settableValue);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (ShouldThrow(overrideSettings, field?.FieldType?.FullName, true, ex))
                        {
                            throw;
                        }
                    }
                }

                foreach (PropertyInfo propertyInfo in type.GetProperties(flags))
                {
                    if (!propertyInfo.CanRead || !propertyInfo.CanWrite)
                    {
                        continue;
                    }
                    shouldSkip = false;
                    shouldSkip = CheckIfShouldSkip(overrideSettings, propertyInfo?.PropertyType?.FullName, shouldSkip);

                    ParameterInfo[] propParameters = propertyInfo.GetIndexParameters();
                    if (!shouldSkip && propParameters?.Where(pp => !pp.IsOptional).Count() > 0)
                    {
                        shouldSkip = true;
                    }

                    if (shouldSkip || ShouldSkipDotNet(type, propertyInfo.PropertyType, propertyInfo.Name))
                    {
                        continue;
                    }

                    object value = propertyInfo.GetValue(instance);
                    ICopyOverrideSettings currentOverride = currentSettings.SingleOrDefault(s => s.FieldValueOverrideType.IsAssignableFrom(propertyInfo.PropertyType) &&
                                                                                            s.ContainingClassType.IsAssignableFrom(type) &&
                                                                                            s.AffectedFieldName == propertyInfo.Name);
                    try
                    {
                        if (currentOverride != null)
                        {
                            if (!currentOverride.ShouldSkipOverrideInsteadOfSet)
                            {
                                var settableValue = currentOverride.UseFieldValueOverrideFunction
                                                                        ? currentOverride.FieldValueOverrideFunction(instance)
                                                                        : currentOverride.FieldValueOverride;
                                propertyInfo.SetValue(copy, settableValue);
                                if (currentOverride.OnlyOverrideFirst)
                                {
                                    overrideSettings.Remove(overrideSettings.Single(s => s.AffectedFieldName == s.AffectedFieldName &&
                                                                                    s.ContainingClassType == s.ContainingClassType && s.FieldValueOverride == s.FieldValueOverride &&
                                                                                    s.FieldValueOverrideType == s.FieldValueOverrideType && s.OnlyOverrideFirst == s.OnlyOverrideFirst));
                                }
                            }
                        }
                        else if (ShouldUseVisitedGraph(overrideSettings) && visited.ContainsKey(value))
                        {
                            var settableValue = visited[value];
                            propertyInfo.SetValue(copy, settableValue);
                        }
                        else
                        {
                            var settableValue = value.Clone(visited, propertyInfo.PropertyType, overrideSettings);
                            propertyInfo.SetValue(copy, settableValue);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (ShouldThrow(overrideSettings, propertyInfo?.PropertyType?.FullName, true, ex))
                        {
                            throw;
                        }
                    }
                }

                type = type.BaseType;
            }

            // call the post copy actions
            if (overrideSettings?.Any(s => s?.PostCopyActions != null) ?? false)
            {
                foreach (ICopyOverrideSettings setting in overrideSettings)
                {
                    if (!(setting?.PostCopyActions?.Any() ?? false))
                    {
                        continue;
                    }

                    // try the exact post copy action
                    if (setting.PostCopyActions.ContainsKey(copy.GetType()))
                    {
                        setting.PostCopyActions[copy.GetType()](instance, copy, expectedType);
                    }
                    // try the default post copy action
                    else if (setting.PostCopyActions.ContainsKey(setting.DefaultPostActionType))
                    {
                        setting.PostCopyActions[setting.DefaultPostActionType](instance, copy, expectedType);
                    }
                }
            }
            return(copy);
        }
        /// <summary>
        /// Creates a deep copy of an object using the supplied dictionary of visited objects as
        /// a source of objects already encountered in the copy traversal. The dictionary of visited
        /// objects is used for holding objects that have already been copied, to avoid erroneous
        /// duplication of parts of the object graph.
        /// </summary>
        /// <param name="instance">The object to be copied.</param>
        /// <param name="visited">The graph of objects visited so far.</param>
        /// <param name="expectedType">The type that should be found.</param>
        /// <param name="overrideSettings">Settings to override the copy logic.</param>
        /// <typeparam name="T">The type of the instance given.</typeparam>
        /// <returns>The copied object.</returns>
        private static T Clone <T>(this T instance, VisitedGraph visited, Type expectedType, IList <ICopyOverrideSettings> overrideSettings = null)
        {
            if (instance == null)
            {
                return(default(T));
            }

            Type   instanceType           = instance.GetType();
            string instanceTypeNameString = instanceType.FullName;
            bool   shouldSkip             = false;

            shouldSkip = CheckIfShouldSkip(overrideSettings, instanceType.FullName, false);

            if (shouldSkip)
            {
                return(default(T));
            }


            if (typeof(Type).IsAssignableFrom(instanceType))
            {
                return(instance);
            }

            Tuple <bool, T> primitiveValue = instance.DeduceInstanceForTypeIfValueType();

            if (primitiveValue.Item1)
            {
                return(primitiveValue.Item2);
            }

            if (instanceType.IsArray)
            {
                int   length = ((Array)(object)instance).Length;
                Array copied = (Array)Activator.CreateInstance(instanceType, length);
                if (ShouldUseVisitedGraph(overrideSettings))
                {
                    visited.Add(instance, copied);
                }
                Type elementType  = instance.GetType().GetElementType();
                bool gotARealType = elementType != null;
                if (!gotARealType)
                {
                    for (int i = 0; i < length || gotARealType; i++)
                    {
                        object current = ((Array)(object)instance).GetValue(i);
                        if (current != null)
                        {
                            elementType  = current.GetType();
                            gotARealType = true;
                        }
                    }
                }
                for (int i = 0; i < length; ++i)
                {
                    object current = ((Array)(object)instance).GetValue(i);
                    copied.SetValue(current.Clone(visited, gotARealType ? elementType : current?.GetType(), overrideSettings), i);
                }
                return((T)(object)copied);
            }
            else if (typeof(IList).IsAssignableFrom(instanceType))
            {
                IList copied      = (IList)Activator.CreateInstance(instanceType);
                Type  elementType = null;
                bool  gotAType    = false;
                if (instanceType.IsGenericType)
                {
                    elementType = instanceType.GetGenericArguments().Single();
                    gotAType    = true;
                }

                if (!gotAType)
                {
                    elementType = instance.GetType().GetElementType();
                    gotAType    = true;
                }

                if (ShouldUseVisitedGraph(overrideSettings))
                {
                    visited.Add(instance, copied);
                }
                foreach (object item in (IList)instance)
                {
                    object clonedItem = item.Clone(visited, elementType, overrideSettings);
                    copied.Add(clonedItem);
                }
                return((T)(object)copied);
            }
            else if (typeof(IDictionary).IsAssignableFrom(instanceType))
            {
                return(Clone(instance, visited, DeduceInstance(instance), expectedType, overrideSettings));
            }
            else if (typeof(IEnumerable).IsAssignableFrom(instanceType))
            {
                // This isn't a fully featured solution IEnumerable and ICollection can still be left out
                Type[]      arguments = instanceType.GenericTypeArguments;
                IEnumerable copied    = (IEnumerable)DeduceInstance(instance);
                if (ShouldUseVisitedGraph(overrideSettings))
                {
                    visited.Add(instance, copied);
                }
                List <object>         test              = new List <object>();
                MethodInfo            castMethod        = typeof(Enumerable).GetMethod("Cast", BindingFlags.Static | BindingFlags.Public);
                MethodInfo            castGenericMethod = castMethod.MakeGenericMethod(arguments);
                IEnumerable <dynamic> casted            = (dynamic)castGenericMethod.Invoke(null, new object[] { ((IEnumerable)instance) });
                copied = ((IEnumerable)instance).Cast <dynamic>().ToList().AsEnumerable();
                return((T)(object)copied);
            }
            else if (typeof(DateTime).IsAssignableFrom(instanceType))
            {
                if (((DateTime)(object)instance) == DateTime.MinValue)
                {
                    // This is a min value allowed by SQL Server for some datetime fields
                    return((T)(object)(new DateTime(1753, 1, 1)));
                }
            }

            return(Clone(instance, visited, DeduceInstance(instance), expectedType, overrideSettings));
        }
예제 #7
0
        private static object Clone(this object instance, VisitedGraph visited, object copy)
        {
            if (visited.ContainsKey(instance))
                return visited[instance];
            else
                visited.Add(instance, copy);

            Type type = instance.GetType();

            while (type != null)
            {
                foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
                {
                    object value = field.GetValue(instance);
                    if (visited.ContainsKey(value))
                        field.SetValue(copy, visited[value]);
                    else
                        field.SetValue(copy, value.Clone(visited));
                }

                type = type.BaseType;
            }
            return copy;
        }
예제 #8
0
        /// <summary>
        /// Creates a deep copy of an object using the supplied dictionary of visited objects as 
        /// a source of objects already encountered in the copy traversal. The dictionary of visited 
        /// objects is used for holding objects that have already been copied, to avoid erroneous 
        /// duplication of parts of the object graph.
        /// </summary>
        /// <param name="instance">The object to be copied.</param>
        /// <param name="visited">The graph of objects visited so far.</param>
        /// <returns></returns>
        private static object Clone(this object instance, VisitedGraph visited)
        {
            if (instance == null)
                return null;

            Type instanceType = instance.GetType();

            if(typeof(Type).IsAssignableFrom(instanceType))
            {
                return instance;
            }

            if (instanceType.IsPointer || instanceType == typeof(Pointer) || instanceType.IsPrimitive || instanceType == typeof(string))
                return instance; // Pointers, primitive types and strings are considered immutable

            if (instanceType.IsArray)
            {
                int length = ((Array)instance).Length;
                Array copied = (Array)Activator.CreateInstance(instanceType, length);
                visited.Add(instance, copied);
                for (int i = 0; i < length; ++i)
                    copied.SetValue(((Array)instance).GetValue(i).Clone(visited), i);
                return copied;
            }

            return Clone(instance, visited, DeduceInstance(instance));
        }