public static object MakeDeepCopy(object source, Type resultType, Func <string, Traverse, Traverse, object> processor = null, string pathRoot = "")
        {
            if (source == null)
            {
                return(null);
            }

            var type = source.GetType();

            if (type.IsPrimitive)
            {
                return(source);
            }

            if (type.IsEnum)
            {
                return(Enum.ToObject(resultType, (int)source));
            }

            if (type.IsGenericType && resultType.IsGenericType)
            {
                var addOperation = FirstMethod(resultType, m => m.Name == "Add" && m.GetParameters().Count() == 1);
                if (addOperation != null)
                {
                    var addableResult  = Activator.CreateInstance(resultType);
                    var addInvoker     = MethodInvoker.GetHandler(addOperation);
                    var newElementType = resultType.GetGenericArguments()[0];
                    var i = 0;
                    foreach (var element in source as IEnumerable)
                    {
                        var iStr       = (i++).ToString();
                        var path       = pathRoot.Length > 0 ? pathRoot + "." + iStr : iStr;
                        var newElement = MakeDeepCopy(element, newElementType, processor, path);
                        addInvoker(addableResult, new object[] { newElement });
                    }
                    return(addableResult);
                }

                // TODO: add dictionaries support
                // maybe use methods in Dictionary<KeyValuePair<TKey,TVal>>
            }

            if (type.IsArray && resultType.IsArray)
            {
                var elementType   = resultType.GetElementType();
                var length        = ((Array)source).Length;
                var arrayResult   = Activator.CreateInstance(resultType, new object[] { length }) as object[];
                var originalArray = source as object[];
                for (var i = 0; i < length; i++)
                {
                    var iStr = i.ToString();
                    var path = pathRoot.Length > 0 ? pathRoot + "." + iStr : iStr;
                    arrayResult[i] = MakeDeepCopy(originalArray[i], elementType, processor, path);
                }
                return(arrayResult);
            }

            var ns = type.Namespace;

            if (ns == "System" || (ns?.StartsWith("System.") ?? false))
            {
                return(source);
            }

            var result = CreateInstance(resultType);

            Traverse.IterateFields(source, result, (name, src, dst) =>
            {
                var path  = pathRoot.Length > 0 ? pathRoot + "." + name : name;
                var value = processor != null ? processor(path, src, dst) : src.GetValue();
                dst.SetValue(MakeDeepCopy(value, dst.GetValueType(), processor, path));
            });
            return(result);
        }
Beispiel #2
0
 public Traverse(Traverse traverse)
 {
     this.traverse = traverse;
 }