internal object Clone(object objectToBeCloned)
        {
            if (objectToBeCloned == null)
            {
                return(null);
            }
            var primaryType = objectToBeCloned.GetType();

            if (primaryType.IsArray && primaryType.GetArrayRank() > 1)
            {
                return(((Array)objectToBeCloned).Clone());
            }

            if (objectToBeCloned.IsInternalObject())
            {
                return(objectToBeCloned);
            }

            object resObject;

            if (primaryType.IsArray || (objectToBeCloned as IList) != null)
            {
                resObject = primaryType.IsArray ? Array.CreateInstance(primaryType.GetIListType(), (objectToBeCloned as Array).Length) : Activator.CreateInstance(primaryType.GetIListType());
                var i     = 0;
                var ilist = resObject as IList;
                var array = resObject as Array;

                foreach (var item in (objectToBeCloned as IList))
                {
                    object clonedIteam = null;
                    if (item != null)
                    {
                        clonedIteam = item.GetType().IsInternalType() ? item : Clone(item);
                    }
                    if (!primaryType.IsArray)
                    {
                        ilist?.Add(clonedIteam);
                    }
                    else
                    {
                        array?.SetValue(clonedIteam, i);
                    }
                    i++;
                }

                foreach (var prop in FastDeepClonerCachedItems.GetFastDeepClonerProperties(primaryType).Where(x => !FastDeepClonerCachedItems.GetFastDeepClonerProperties(typeof(List <string>)).Any(a => a.Key == x.Key)))
                {
                    var property = prop.Value;
                    if (!property.CanRead || property.FastDeepClonerIgnore)
                    {
                        continue;
                    }
                    var value = property.GetValue(objectToBeCloned);
                    if (value == null)
                    {
                        continue;
                    }
                    var clonedIteam = value.GetType().IsInternalType() ? value : Clone(value);
                    property.SetValue(resObject, clonedIteam);
                }
            }
            else if (objectToBeCloned is IDictionary)
            {
                resObject = Activator.CreateInstance(primaryType);
                var resDic     = resObject as IDictionary;
                var dictionary = (IDictionary)objectToBeCloned;
                foreach (var key in dictionary.Keys)
                {
                    var    item        = dictionary[key];
                    object clonedIteam = null;
                    if (item != null)
                    {
                        clonedIteam = item.GetType().IsInternalType() ? item : Clone(item);
                    }
                    resDic?.Add(key, clonedIteam);
                }
            }
            else if (primaryType.IsAnonymousType()) // dynamic types
            {
                var props = FastDeepClonerCachedItems.GetFastDeepClonerProperties(primaryType);
                resObject = new ExpandoObject();
                var d = resObject as IDictionary <string, object>;
                foreach (var prop in props.Values)
                {
                    var item  = prop.GetValue(objectToBeCloned);
                    var value = item == null || prop.IsInternalType || (item?.IsInternalObject() ?? true) ? item : Clone(item);
                    if (!d.ContainsKey(prop.Name))
                    {
                        d.Add(prop.Name, value);
                    }
                }
            }
            else
            {
                resObject = ReferenceTypeClone((_settings.FieldType == FieldType.FieldInfo ? FastDeepClonerCachedItems.GetFastDeepClonerFields(primaryType) : FastDeepClonerCachedItems.GetFastDeepClonerProperties(primaryType)), primaryType, objectToBeCloned);
                if (_settings.FieldType == FieldType.Both)
                {
                    resObject = ReferenceTypeClone(FastDeepClonerCachedItems.GetFastDeepClonerFields(primaryType).Values.ToList().Where(x => !FastDeepClonerCachedItems.GetFastDeepClonerProperties(primaryType).ContainsKey(x.Name)).ToDictionary(x => x.Name, x => x), primaryType, objectToBeCloned, resObject);
                }
            }

            return(resObject);
        }
        internal object CloneTo(object itemToClone, object CloneToItem)
        {
            var identifier = CloneToItem.GetFastDeepClonerIdentifier();

            if (identifier != null && _alreadyCloned.ContainsKey(identifier))
            {
                return(_alreadyCloned[identifier]);
            }

            if (identifier != null)
            {
                _alreadyCloned.Add(identifier, CloneToItem);
            }

            var type2  = CloneToItem.GetType();
            var props2 = FastDeepClonerCachedItems.GetFastDeepClonerProperties(type2);

            foreach (var prop2 in props2)
            {
                if (!prop2.Value.CanWrite)
                {
                    continue;
                }
                var item = itemToClone;
                var prop = item.GetType().GetProperty(prop2.Key);
                foreach (var attr in prop2.Value.GetCustomAttributes <FastDeepClonerColumn>())
                {
                    var strSplit = attr.ColumnName.Split('.');
                    for (var i = 0; i < strSplit.Length; i++)
                    {
                        var p = item.GetType().GetProperty(strSplit[i]);
                        if (p != null)
                        {
                            prop = p;

                            if (i != strSplit.Length - 1)
                            {
                                item = p.GetValue(item);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }

                if (prop != null)
                {
                    var value = prop.GetValue(item);
                    if (value == null)
                    {
                        continue;
                    }
                    if (prop.PropertyType.IsInternalType())
                    {
                        prop2.Value.SetValue(CloneToItem, FastDeepClonerCachedItems.Value(value, prop2.Value.PropertyType, true));
                    }
                    else if (prop.PropertyType == prop2.Value.PropertyType)
                    {
                        prop2.Value.SetValue(CloneToItem, value.Clone());
                    }
                    else if (prop.PropertyType.GetIListType() == prop.PropertyType && prop2.Value.PropertyType.GetIListType() == prop2.Value.PropertyType) // if not list
                    {
                        var value2 = prop2.Value.GetValue(item);
                        if (value2 == null)
                        {
                            value2 = prop2.Value.PropertyType.CreateInstance();
                        }
                        prop2.Value.SetValue(CloneToItem, CloneTo(value, value2));
                    }
                }
            }

            return(CloneToItem);
        }
 /// <summary>
 /// Convert Value from Type to Type
 /// when fail a default value will be loaded.
 /// can handle all known types like datetime, time span, string, long etc
 /// ex
 ///  "1115rd" to int? will return null
 ///  "152" to int? 152
 /// </summary>
 /// <param name="value"></param>
 /// <param name="datatype">eg typeof(int?)</param>
 /// <param name="defaultValue"></param>
 /// <returns></returns>
 public static object ValueConverter(this object value, Type datatype, object defaultValue = null)
 {
     return(FastDeepClonerCachedItems.Value(value, datatype, true, defaultValue));
 }
 /// <summary>
 /// Get DefaultValue by type
 /// </summary>
 /// <param name="propertyType"></param>
 /// <param name="defaultValue"></param>
 /// <returns></returns>
 public static object ValueByType(this Type propertyType, object defaultValue = null)
 {
     return(FastDeepClonerCachedItems.ValueByType(propertyType, defaultValue));
 }
 /// <summary>
 /// Convert Value from Type to Type
 /// when fail a default value will be loaded.
 /// can handle all known types like datetime, time span, string, long etc
 /// ex
 ///  "1115rd" to int? will return null
 ///  "152" to int? 152
 /// </summary>
 /// <typeparam name="T"></typeparam>
 /// <param name="value"></param>
 /// <param name="defaultValue"></param>
 /// <returns></returns>
 public static T ValueConverter <T>(this object value, object defaultValue = null)
 {
     return((T)FastDeepClonerCachedItems.Value(value, typeof(T), true, defaultValue));
 }
 /// <summary>
 /// This will handle only internal types
 /// and noneinternal type must be of the same type to be cloned
 /// </summary>
 /// <param name="itemToClone"></param>
 /// <param name="CloneToItem"></param>
 public static void CloneTo(this object itemToClone, object CloneToItem)
 {
     FastDeepClonerCachedItems.CloneTo(itemToClone, CloneToItem);
 }
 /// <summary>
 /// Get Property by name
 /// </summary>
 /// <param name="type"></param>
 /// <param name="name"></param>
 /// <returns></returns>
 public static IFastDeepClonerProperty GetProperty(this Type type, string name)
 {
     return(FastDeepClonerCachedItems.GetFastDeepClonerProperties(type).ContainsKey(name)
         ? FastDeepClonerCachedItems.GetFastDeepClonerProperties(type)[name]
         : null);
 }
 /// <summary>
 /// will return propertyInfo from the cached propertyInfo. Get and set value is much faster.
 /// </summary>
 /// <param name="type"></param>
 /// <returns></returns>
 public static List <IFastDeepClonerProperty> GetFastDeepClonerProperties(this Type type)
 {
     return(FastDeepClonerCachedItems.GetFastDeepClonerProperties(type).Values.ToList());
 }
 /// <summary>
 /// Clear cached data
 /// </summary>
 public static void CleanCachedItems()
 {
     FastDeepClonerCachedItems.CleanCachedItems();
 }