internal static Type GetIListItemType(this Type type) { if (CachedIListInternalTypes.ContainsKey(type)) { return(CachedIListInternalTypes[type]); } if (type.IsArray) { CachedIListInternalTypes.Add(type, type.GetElementType()); } else { if (type.GenericTypeArguments.Any()) { CachedIListInternalTypes.Add(type, type.GenericTypeArguments.First()); } else if (type.FullName.Contains("List`1") || type.FullName.Contains("ObservableCollection`1")) { CachedIListInternalTypes.Add(type, typeof(List <>).MakeGenericType(type.GetRuntimeProperty("Item").PropertyType)); } else { CachedIListInternalTypes.Add(type, type); } } return(CachedIListInternalTypes[type]); }
internal static object ConvertToInterface(this Type interfaceType, object item) { var type = item.GetType(); if (interfaceType.IsAssignableFrom(type)) { return(item); } var props = DeepCloner.GetFastDeepClonerProperties(type); var args = new SafeValueType <string, object>(); foreach (var iProp in DeepCloner.GetFastDeepClonerProperties(interfaceType)) { var p = DeepCloner.GetProperty(type, iProp.Name); if (p == null) { continue; } var value = p.GetValue(item); if (value == null || p.PropertyType == iProp.PropertyType) { args.Add(iProp.Name, value); continue; } try { if (iProp.PropertyType.IsInterface) { args.Add(iProp.Name, iProp.PropertyType.InterFaceConverter(value)); } else { args.Add(iProp.Name, Convert.ChangeType(value, DeepCloner.GetProperty(interfaceType, p.Name).PropertyType)); } } catch (Exception e) { var iType = iProp.PropertyType; throw new Exception($"Property {p.Name} has different type then the interface which is of type {iProp.PropertyType}. \n (Convert.ChangeType) could not convert from {p.PropertyType} to {iType}. \n Orginal Exception: {e.Message}"); } } var key = $"{(type.IsAnonymousType() ? string.Join(" | ", props.Select(x => x.FullName).ToArray()) : type.FullName)} | {interfaceType.FullName}"; var newtype = CachedConvertedObjectToInterface.ContainsKey(key) ? CachedConvertedObjectToInterface[key] : CachedConvertedObjectToInterface.GetOrAdd(key, FastDeepCloner.ConvertToInterfaceTypeGenerator.Convert(interfaceType, type)); var returnValue = Creator(newtype, false, args.Values.ToArray()); var constructor = GetConstructorInfo(newtype, args.Values.ToArray()); if (constructor == null) { foreach (var p in args) { DeepCloner.GetProperty(newtype, p.Key).SetValue(returnValue, args[p.Key]); } } return(returnValue); }
internal static Dictionary <string, IFastDeepClonerProperty> GetFastDeepClonerProperties(this Type primaryType, ICollection <PropertyInfo> ignorePropertyInfos = null) { ignorePropertyInfos = ignorePropertyInfos ?? new PropertyInfo[0]; if (!CachedPropertyInfo.ContainsKey(primaryType) && ignorePropertyInfos.None()) { CachedPropertyInfo.Add(primaryType, GetPropertiesInternal(primaryType, ignorePropertyInfos)); } return(ignorePropertyInfos.None() ? CachedPropertyInfo[primaryType] : GetPropertiesInternal(primaryType, ignorePropertyInfos)); }
internal static string GetFastDeepClonerIdentifier(this object o) { if (o == null) { return(null); } var type = o.GetType(); var p = CachedFastDeepClonerIdentifier.ContainsKey(type) ? CachedFastDeepClonerIdentifier[type] : CachedFastDeepClonerIdentifier.GetOrAdd(type, DeepCloner.GetFastDeepClonerProperties(type).FirstOrDefault(x => x.FastDeepClonerPrimaryIdentifire)); return(p == null ? null : type.FullName + type.Name + p.Name + p.FullName + p.GetValue(o)); }
internal static Type GetFastType(this string typeName, string assembly) { if (string.IsNullOrEmpty(assembly)) { throw new Exception("AssemblyName cannot be empty"); } if (!assembly.ToLower().EndsWith(".dll")) { assembly += ".dll"; } var key = typeName + assembly; if (CachedStringTypes.ContainsKey(key)) { return(CachedStringTypes.Get(key)); } var type = Type.GetType($"{typeName}, {assembly.Substring(0, assembly.ToLower().IndexOf(".dll"))}"); if (type != null) { if (!CachedAssembly.ContainsKey(assembly)) { CachedAssembly.TryAdd(assembly, type.Assembly); } return(CachedStringTypes.GetOrAdd(key, type)); } else if (!CachedAssembly.ContainsKey(assembly)) { CachedAssembly.TryAdd(assembly, Assembly.LoadFrom(assembly)); } return(CachedStringTypes.GetOrAdd(key, CachedAssembly.Get(assembly).GetType(typeName, true, true))); }
internal static ConstructorInfo GetConstructorInfo(this Type type, params object[] parameters) { var key = type.FullName + string.Join("", parameters?.Select(x => x.GetType())); if (ConstructorInfos.ContainsKey(key)) { return(ConstructorInfos.Get(key)); } #if !NETSTANDARD1_3 return(ConstructorInfos.GetOrAdd(key, parameters == null ? type.GetConstructor(Type.EmptyTypes) : type.GetConstructor(parameters.Select(x => x.GetType()).ToArray()))); #else ConstructorInfo constructor = null; foreach (var cr in type.GetTypeInfo().DeclaredConstructors) { var index = 0; var args = cr.GetParameters(); if (args.Length == parameters.Length) { var apply = true; foreach (var pr in args) { var prType = pr.ParameterType; var paramType = parameters[index].GetType(); if (prType != paramType) { try { Convert.ChangeType(parameters[index], prType); } catch { apply = false; break; } } index++; } if (apply) { constructor = cr; } } } return(ConstructorInfos.GetOrAdd(key, constructor)); #endif }
private object ReferenceTypeClone(Dictionary <string, IFastDeepClonerProperty> properties, Type primaryType, object objectToBeCloned, object appendToValue = null) { var identifier = objectToBeCloned.GetFastDeepClonerIdentifier(); if (identifier != null && _alreadyCloned.ContainsKey(identifier)) { return(_alreadyCloned[identifier]); } var resObject = appendToValue ?? _settings.OnCreateInstance(primaryType); if (identifier != null) { _alreadyCloned.Add(identifier, resObject); } foreach (var property in properties.Values) { if (!property.CanRead || property.FastDeepClonerIgnore) { continue; } var value = property.GetValue(objectToBeCloned); if (value == null) { continue; } if ((property.IsInternalType || value.GetType().IsInternalType())) { property.SetValue(resObject, value); } else { if (_settings.CloneLevel == CloneLevel.FirstLevelOnly) { continue; } property.SetValue(resObject, Clone(value)); } } return(resObject); }
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]); }
internal static INotifyPropertyChanged ProxyCreator(this Type type) { lock (ProxyTypes) { try { MethodInfo method; if (ProxyTypesPropertyChanged.ContainsKey(type)) { method = ProxyTypesPropertyChanged[type]; } else { method = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(x => x.GetParameters().Any(a => a.ParameterType == typeof(object)) && x.GetParameters().Any(a => a.ParameterType == typeof(PropertyChangedEventArgs))); ProxyTypesPropertyChanged.TryAdd(type, method); } INotifyPropertyChanged item; if (ProxyTypes.ContainsKey(type)) { item = ProxyTypes[type].Creator() as INotifyPropertyChanged; } else { ProxyTypes.Add(type, INotifyPropertyChangedProxyTypeGenerator.GenerateProxy(type)); item = ProxyTypes[type].Creator() as INotifyPropertyChanged; } if (method != null) { item.PropertyChanged += (PropertyChangedEventHandler)Delegate.CreateDelegate(typeof(PropertyChangedEventHandler), item, method); } return(item); } catch (Exception e) { throw e; } } }
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); }
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; } }
internal static ConstructorInfo GetConstructorInfo(this Type type, params object[] parameters) { IEnumerable <ConstructorInfo> constructors; var key = type.FullName + string.Join("", parameters?.Select(x => x.GetType())); if (ConstructorInfo.ContainsKey(key)) { return(ConstructorInfo.Get(key)); } #if !NETSTANDARD1_3 constructors = type.GetConstructors(); #else constructors = type.GetTypeInfo().DeclaredConstructors; #endif ConstructorInfo constructor = null; foreach (var cr in constructors) { var index = 0; var args = cr.GetParameters(); if (args.Length == parameters.Length) { var apply = true; foreach (var pr in args) { var prType = pr.ParameterType; var paramType = parameters[index].GetType(); if (prType != paramType) { try { if ((prType.IsInternalType() && paramType.IsInternalType())) { Convert.ChangeType(parameters[index], prType); } else { if (prType.GetTypeInfo().IsInterface&& paramType.GetTypeInfo().IsAssignableFrom(prType.GetTypeInfo())) { continue; } else { apply = false; break; } } } catch { apply = false; break; } } index++; } if (apply) { constructor = cr; } } } return(ConstructorInfo.GetOrAdd(key, constructor)); }