/// <summary> /// Tries to convert the input object to the output type using TypeConverters. If the destination type is a superclass of the input type, /// if will use <see cref="Convert.ChangeType(object,System.Type)"/>. /// </summary> /// <param name="input">The input.</param> /// <param name="destinationType">Type of the destination.</param> /// <returns></returns> public static AttemptTuple <object> TryConvertTo(this object input, Type destinationType) { if (input == null) { return(AttemptTuple <object> .False); } if (destinationType == typeof(object)) { return(new AttemptTuple <object>(true, input)); } if (input.GetType() == destinationType) { return(new AttemptTuple <object>(true, input)); } if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable <>)) { if (TypeFinder.IsTypeAssignableFrom(destinationType, input.GetType()) && TypeFinder.IsTypeAssignableFrom <IConvertible>(input)) { var casted = Convert.ChangeType(input, destinationType); return(new AttemptTuple <object>(true, casted)); } } var inputConverter = TypeDescriptor.GetConverter(input); if (inputConverter != null) { if (inputConverter.CanConvertTo(destinationType)) { return(new AttemptTuple <object>(true, inputConverter.ConvertTo(input, destinationType))); } } if (destinationType == typeof(bool)) { var boolConverter = new CustomBooleanTypeConverter(); if (boolConverter.CanConvertFrom(input.GetType())) { return(new AttemptTuple <object>(true, boolConverter.ConvertFrom(input))); } } var outputConverter = TypeDescriptor.GetConverter(destinationType); if (outputConverter != null) { if (outputConverter.CanConvertFrom(input.GetType())) { return(new AttemptTuple <object>(true, outputConverter.ConvertFrom(input))); } } try { if (TypeFinder.IsTypeAssignableFrom <IConvertible>(input)) { var casted = Convert.ChangeType(input, destinationType); return(new AttemptTuple <object>(true, casted)); } } catch (Exception) { /* Swallow */ } return(AttemptTuple <object> .False); }
/// <summary> /// Copies an object graph. /// </summary> /// <param name="source">The source.</param> /// <param name="targetType">Type of the target.</param> /// <param name="factory">The factory.</param> /// <param name="recurseCount">The recurse count.</param> /// <param name="hideErrorsInPartialTrust">The hide errors in partial trust.</param> /// <returns></returns> public static CloneOf <object> DeepCopy(this object source, Type targetType, Func <object> factory = null, int recurseCount = 0, bool?hideErrorsInPartialTrust = true) { if (recurseCount > 50) { throw new InvalidOperationException("Cannot clone an object graph greater than 50 objects in depth"); } var isPartialClone = false; //grab the type and create a new instance of that type var sourceType = targetType; var target = factory == null?CreateObject(targetType) : factory.Invoke(); //grab the properties var discoverableProperties = TypeFinder.CachedDiscoverableProperties(sourceType); //iterate over the properties and if it has a 'set' method assign it from the source TO the target foreach (var info in discoverableProperties) { // We don't check IsAssembly and IsFamily on the get method to ensure we don't try internal / private get accessors // because we rely on catching an exception instead - without comparing the PermissionSets of this code with the target // code IsAssembly and IsFamily don't give a clear picture of whether we can read it with reflection anyway // The GetMethod might have security parameters on it or might be internal. If security is tight // on the get method, it won't be returned, so check for null and double-check it's not internal var methodGetter = TypeFinder.DynamicMemberAccess.GetterDelegate(info); // We don't check !methodInfo.IsAssembly && !methodInfo.IsFamily here, instead leaving that to the try-catch // so that we can report back to the caller. If it was easier to check our PermissionSet with that of the type // we're looking at, I'd avoid a try-catch, but clarifying the PermissionSet requires full trust(!) - APN if (methodGetter != null) { try { var propertyValue = info.GetValue(source, null); var setter = TypeFinder.DynamicMemberAccess.SetterDelegate(info, true); SetValue(info, info.PropertyType, target, propertyValue, setter.Invoke, recurseCount); } catch (MemberAccessException) { if (hideErrorsInPartialTrust.HasValue && hideErrorsInPartialTrust.Value) { isPartialClone = true; continue; } throw; } } } // grab protected fields var discoverableFields = TypeFinder.CachedDiscoverableFields(sourceType); // Iterate over the properties to see if it is not readonly foreach (var fieldInfo in discoverableFields) { var localFieldInfoCopy = fieldInfo; try { var sourceValue = fieldInfo.GetValue(source); SetValue(fieldInfo, fieldInfo.FieldType, target, sourceValue, localFieldInfoCopy.SetValue, recurseCount); } catch (FieldAccessException) { if (hideErrorsInPartialTrust.HasValue && hideErrorsInPartialTrust.Value) { isPartialClone = true; continue; } throw; } } //return the new item return(new CloneOf <object>(isPartialClone, target)); }
private static bool IsNotCloneable(MemberInfo info) { return(TypeFinder.IsTypeAssignableFrom <Delegate>(info.DeclaringType)); }
private static Func <object> GetObjectFactory(Type type) { if (type.IsInterface) { throw new InvalidOperationException("Cannot instantiate an interface ({0})".InvariantFormat(type.FullName)); } var isFullyTrusted = AppDomain.CurrentDomain.IsFullyTrusted; var constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(x => x.GetParameters().Count() == 0 && (isFullyTrusted || (!isFullyTrusted && !x.IsSecurityCritical && !x.IsSecuritySafeCritical))) .FirstOrDefault(); if (constructor != null) { // This catch block is here because there are certain types of constructor that I can't grab via properties on ConstructorInfo // for example NullViewLocationCache is a sealed internal type with no constructor, yet a constructor is found using the above // method! try { return(() => constructor.Invoke(new object[0])); } catch (SecurityException ex) { LogSecurityException(type, isFullyTrusted, ex); } catch (MemberAccessException ex) { ThrowIfFullTrust(type, isFullyTrusted, ex); } } if (isFullyTrusted) { return(() => FormatterServices.GetUninitializedObject(type)); } // We're in partial trust, but haven't found a default constructor, so find the first constructor with nullable parameter types var nearestConstructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .OrderBy(x => x.GetParameters().Count()) .FirstOrDefault(); if (nearestConstructor != null) { var paramValues = nearestConstructor.GetParameters().Select(x => TypeFinder.IsImplicitValueType(x.ParameterType) ? x.ParameterType.GetDefaultValue() : CreateObject(x.ParameterType)).ToArray(); try { return(() => nearestConstructor.Invoke(paramValues)); } catch (SecurityException ex) { LogSecurityException(type, isFullyTrusted, ex); } catch (MemberAccessException ex) { ThrowIfFullTrust(type, isFullyTrusted, ex); } } throw new InvalidOperationException( "Cannot find a default constructor for {0}, and since this AppDomain is not fully trusted, also tried to find another constructor, but that failed too. Come to think of it, how do YOU make this object?".InvariantFormat(type.FullName)); }