/// <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))); } }
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); }