internal static Dictionary <string, IFastDeepClonerProperty> GetFastDeepClonerProperties(this Type primaryType)
 {
     if (!CachedPropertyInfo.ContainsKey(primaryType))
     {
         var properties = new SafeValueType <string, IFastDeepClonerProperty>();
         if (primaryType.GetTypeInfo().BaseType != null && primaryType.GetTypeInfo().BaseType.Name != "Object")
         {
             primaryType.GetRuntimeProperties().Where(x => properties.TryAdd(x.Name, new FastDeepClonerProperty(x))).ToList();
             primaryType.GetTypeInfo().BaseType.GetRuntimeProperties().Where(x => properties.TryAdd(x.Name, new FastDeepClonerProperty(x))).ToList();
         }
         else
         {
             primaryType.GetRuntimeProperties().Where(x => properties.TryAdd(x.Name, new FastDeepClonerProperty(x))).ToList();
         }
         CachedPropertyInfo.Add(primaryType, properties);
     }
     return(CachedPropertyInfo[primaryType]);
 }
        private static SafeValueType <string, IFastDeepClonerProperty> GetPropertiesInternal(Type primaryType, ICollection <PropertyInfo> ignorePropertyInfos)
        {
            var properties = new SafeValueType <string, IFastDeepClonerProperty>();

            if (primaryType.GetTypeInfo().BaseType != null && primaryType.GetTypeInfo().BaseType.Name != "Object")
            {
                primaryType.GetRuntimeProperties().Except(ignorePropertyInfos).ToList()
                .ForEach(x => properties.TryAdd(x.Name, new FastDeepClonerProperty(x)));
                primaryType.GetTypeInfo().BaseType.GetRuntimeProperties().Except(ignorePropertyInfos).ToList()
                .ForEach(x => properties.TryAdd(x.Name, new FastDeepClonerProperty(x)));
            }
            else
            {
                primaryType.GetRuntimeProperties().Except(ignorePropertyInfos).ToList()
                .ForEach(x => properties.TryAdd(x.Name, new FastDeepClonerProperty(x)));
            }

            return(properties);
        }
        internal static object Creator(this Type type, bool validateArgs = true, params object[] parameters)
        {
            try
            {
                var key         = type.FullName + string.Join("", parameters?.Select(x => x.GetType().FullName));
                var constructor = type.GetConstructorInfo(parameters ?? new object[0]);
                if (constructor == null && parameters?.Length > 0)
                {
                    constructor = type.GetConstructorInfo(new object[0]);
                }
                if (constructor != null)
                {
                    var constParam = constructor.GetParameters();
                    if (validateArgs && (parameters?.Any() ?? false))
                    {
                        for (var i = 0; i < parameters.Length; i++)
                        {
                            if (constParam.Length <= i)
                            {
                                continue;
                            }
                            if (constParam[i].ParameterType != parameters[i].GetType())
                            {
                                try
                                {
                                    parameters[i] = Convert.ChangeType(parameters[i], constParam[i].ParameterType);
                                }
                                catch
                                {
                                    // Ignore
                                }
                            }
                        }
                    }

#if NETSTANDARD2_0 || NETSTANDARD1_3 || NETSTANDARD1_5
                    if (!constParam.Any())
                    {
                        if (CachedConstructor.ContainsKey(key))
                        {
                            return(CachedConstructor[key]());
                        }
                    }
                    else if (CachedConstructorWithParameter.ContainsKey(key))
                    {
                        return(CachedConstructorWithParameter[key](parameters));
                    }

                    if (!(parameters?.Any() ?? false))
                    {
                        return(CachedConstructor.GetOrAdd(key, Expression.Lambda <Func <object> >(Expression.New(type)).Compile())());
                    }
                    else
                    {
                        // Create a single param of type object[].
                        ParameterExpression param = Expression.Parameter(typeof(object[]), "args");

                        // Pick each arg from the params array and create a typed expression of them.
                        Expression[] argsExpressions = new Expression[constParam.Length];

                        for (int i = 0; i < constParam.Length; i++)
                        {
                            Expression index            = Expression.Constant(i);
                            Type       paramType        = constParam[i].ParameterType;
                            Expression paramAccessorExp = Expression.ArrayIndex(param, index);
                            Expression paramCastExp     = Expression.Convert(paramAccessorExp, paramType);
                            argsExpressions[i] = paramCastExp;
                        }


                        return(CachedConstructorWithParameter.GetOrAdd(key, Expression.Lambda <Func <object[], object> >(Expression.New(constructor, argsExpressions), param).Compile())(parameters));
                    }
#else
                    if (!constParam.Any())
                    {
                        if (CachedDynamicMethod.ContainsKey(key))
                        {
                            return(CachedDynamicMethod[key]());
                        }
                    }
                    else if (CachedDynamicMethodWithParameters.ContainsKey(key))
                    {
                        return(CachedDynamicMethodWithParameters[key](parameters));
                    }

                    lock (CachedDynamicMethod)
                    {
                        var dynamicMethod = new System.Reflection.Emit.DynamicMethod("CreateInstance", type, (constParam.Any() ? new Type[] { typeof(object[]) } : Type.EmptyTypes), true);
                        System.Reflection.Emit.ILGenerator ilGenerator = dynamicMethod.GetILGenerator();


                        if (constructor.GetParameters().Any())
                        {
                            for (int i = 0; i < constParam.Length; i++)
                            {
                                Type paramType = constParam[i].ParameterType;
                                ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);    // Push array (method argument)
                                ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, i);  // Push i
                                ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref); // Pop array and i and push array[i]
                                if (paramType.IsValueType)
                                {
                                    ilGenerator.Emit(System.Reflection.Emit.OpCodes.Unbox_Any, paramType); // Cast to Type t
                                }
                                else
                                {
                                    ilGenerator.Emit(System.Reflection.Emit.OpCodes.Castclass, paramType); //Cast to Type t
                                }
                            }
                        }


                        //ilGenerator.Emit(System.Reflection.Emit.OpCodes.Nop);
                        ilGenerator.Emit(System.Reflection.Emit.OpCodes.Newobj, constructor);
                        //ilGenerator.Emit(System.Reflection.Emit.OpCodes.Stloc_1); // nothing
                        ilGenerator.Emit(System.Reflection.Emit.OpCodes.Ret);

                        if (!constParam.Any())
                        {
                            return(CachedDynamicMethod.GetOrAdd(key, (ObjectActivator)dynamicMethod.CreateDelegate(typeof(ObjectActivator)))());
                        }
                        else
                        {
                            return(CachedDynamicMethodWithParameters.GetOrAdd(key, (ObjectActivatorWithParameters)dynamicMethod.CreateDelegate(typeof(ObjectActivatorWithParameters)))(parameters));
                        }
                    }
#endif
                }
                else
                {
#if !NETSTANDARD1_3
                    return(FormatterServices.GetUninitializedObject(type));
#else
                    try
                    {
                        if (CachedConstructor.ContainsKey(key))
                        {
                            return(CachedConstructor[key]());
                        }
                        return(CachedConstructor.GetOrAdd(key, Expression.Lambda <Func <object> >(Expression.New(type)).Compile())());
                    }
                    catch
                    {
                        throw new Exception("DeepClonerError: Default constructor is require for NETSTANDARD1_3 for type " + type.FullName);
                    }
#endif
                }
            }
            catch (Exception e)
            {
                throw e;
            }
        }