/// <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 Attempt <object> TryConvertTo(this object input, Type destinationType) { if (input == null) { return(Attempt <object> .False); } if (destinationType == typeof(object)) { return(new Attempt <object>(true, input)); } if (input.GetType() == destinationType) { return(new Attempt <object>(true, input)); } if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable <>)) { if (TypeHelper.IsTypeAssignableFrom(destinationType, input.GetType()) && TypeHelper.IsTypeAssignableFrom <IConvertible>(input)) { var casted = Convert.ChangeType(input, destinationType); return(new Attempt <object>(true, casted)); } } var inputConverter = TypeDescriptor.GetConverter(input); if (inputConverter.CanConvertTo(destinationType)) { try { var converted = inputConverter.ConvertTo(input, destinationType); return(new Attempt <object>(true, converted)); } catch (Exception e) { return(new Attempt <object>(e)); } } if (destinationType == typeof(bool)) { var boolConverter = new CustomBooleanTypeConverter(); if (boolConverter.CanConvertFrom(input.GetType())) { try { var converted = boolConverter.ConvertFrom(input); return(new Attempt <object>(true, converted)); } catch (Exception e) { return(new Attempt <object>(e)); } } } var outputConverter = TypeDescriptor.GetConverter(destinationType); if (outputConverter.CanConvertFrom(input.GetType())) { try { var converted = outputConverter.ConvertFrom(input); return(new Attempt <object>(true, converted)); } catch (Exception e) { return(new Attempt <object>(e)); } } if (TypeHelper.IsTypeAssignableFrom <IConvertible>(input)) { try { var casted = Convert.ChangeType(input, destinationType); return(new Attempt <object>(true, casted)); } catch (Exception e) { return(new Attempt <object>(e)); } } return(Attempt <object> .False); }
/// <summary> /// Attempts to convert the input object to the output type. /// </summary> /// <remarks>This code is an optimized version of the original Umbraco method</remarks> /// <param name="input">The input.</param> /// <param name="target">The type to convert to</param> /// <returns>The <see cref="Attempt{Object}"/></returns> public static Attempt <object> TryConvertTo(this object input, Type target) { if (target == null) { return(Attempt <object> .Fail()); } try { if (input == null) { // Nullable is ok if (target.IsGenericType && GetCachedGenericNullableType(target) != null) { return(Attempt <object> .Succeed(null)); } // Reference types are ok return(Attempt <object> .SucceedIf(target.IsValueType == false, null)); } var inputType = input.GetType(); // Easy if (target == typeof(object) || inputType == target) { return(Attempt.Succeed(input)); } // Check for string so that overloaders of ToString() can take advantage of the conversion. if (target == typeof(string)) { return(Attempt <object> .Succeed(input.ToString())); } // If we've got a nullable of something, we try to convert directly to that thing. // We cache the destination type and underlying nullable types // Any other generic types need to fall through if (target.IsGenericType) { var underlying = GetCachedGenericNullableType(target); if (underlying != null) { // Special case for empty strings for bools/dates which should return null if an empty string. if (input is string inputString) { //TODO: Why the check against only bool/date when a string is null/empty? In what scenario can we convert to another type when the string is null or empty other than just being null? if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool))) { return(Attempt <object> .Succeed(null)); } } // Recursively call into this method with the inner (not-nullable) type and handle the outcome var inner = input.TryConvertTo(underlying); // And if sucessful, fall on through to rewrap in a nullable; if failed, pass on the exception if (inner.Success) { input = inner.Result; // Now fall on through... } else { return(Attempt <object> .Fail(inner.Exception)); } } } else { // target is not a generic type if (input is string inputString) { // Try convert from string, returns an Attempt if the string could be // processed (either succeeded or failed), else null if we need to try // other methods var result = TryConvertToFromString(inputString, target); if (result.HasValue) { return(result.Value); } } // TODO: Do a check for destination type being IEnumerable<T> and source type implementing IEnumerable<T> with // the same 'T', then we'd have to find the extension method for the type AsEnumerable() and execute it. if (GetCachedCanAssign(input, inputType, target)) { return(Attempt.Succeed(Convert.ChangeType(input, target))); } } if (target == typeof(bool)) { if (GetCachedCanConvertToBoolean(inputType)) { return(Attempt.Succeed(CustomBooleanTypeConverter.ConvertFrom(input))); } } var inputConverter = GetCachedSourceTypeConverter(inputType, target); if (inputConverter != null) { return(Attempt.Succeed(inputConverter.ConvertTo(input, target))); } var outputConverter = GetCachedTargetTypeConverter(inputType, target); if (outputConverter != null) { return(Attempt.Succeed(outputConverter.ConvertFrom(input))); } if (target.IsGenericType && GetCachedGenericNullableType(target) != null) { // cannot Convert.ChangeType as that does not work with nullable // input has already been converted to the underlying type - just // return input, there's an implicit conversion from T to T? anyways return(Attempt.Succeed(input)); } // Re-check convertables since we altered the input through recursion if (input is IConvertible convertible2) { return(Attempt.Succeed(Convert.ChangeType(convertible2, target))); } } catch (Exception e) { return(Attempt <object> .Fail(e)); } return(Attempt <object> .Fail()); }
/// <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 Attempt <object> TryConvertTo(this object input, Type destinationType) { if (input == null) { return(Attempt <object> .Fail()); } if (destinationType == typeof(object)) { return(Attempt.Succeed(input)); } if (input.GetType() == destinationType) { return(Attempt.Succeed(input)); } //check for string so that overloaders of ToString() can take advantage of the conversion. if (destinationType == typeof(string)) { return(Attempt <object> .Succeed(input.ToString())); } // if we've got a nullable of something, we try to convert directly to that thing. if (destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof(Nullable <>)) { var underlyingType = Nullable.GetUnderlyingType(destinationType); //special case for empty strings for bools/dates which should return null if an empty string var asString = input as string; if (asString != null && string.IsNullOrEmpty(asString) && (underlyingType == typeof(DateTime) || underlyingType == typeof(bool))) { return(Attempt <object> .Succeed(null)); } // recursively call into myself with the inner (not-nullable) type and handle the outcome var nonNullable = input.TryConvertTo(underlyingType); // and if sucessful, fall on through to rewrap in a nullable; if failed, pass on the exception if (nonNullable.Success) { input = nonNullable.Result; // now fall on through... } else { return(Attempt <object> .Fail(nonNullable.Exception)); } } // we've already dealed with nullables, so any other generic types need to fall through if (!destinationType.IsGenericType) { if (input is string) { var result = TryConvertToFromString(input as string, destinationType); // if we processed the string (succeed or fail), we're done if (result.HasValue) { return(result.Value); } } //TODO: Do a check for destination type being IEnumerable<T> and source type implementing IEnumerable<T> with // the same 'T', then we'd have to find the extension method for the type AsEnumerable() and execute it. if (TypeHelper.IsTypeAssignableFrom(destinationType, input.GetType()) && TypeHelper.IsTypeAssignableFrom <IConvertible>(input)) { try { var casted = Convert.ChangeType(input, destinationType); return(Attempt.Succeed(casted)); } catch (Exception e) { return(Attempt <object> .Fail(e)); } } } var inputConverter = TypeDescriptor.GetConverter(input); if (inputConverter.CanConvertTo(destinationType)) { try { var converted = inputConverter.ConvertTo(input, destinationType); return(Attempt.Succeed(converted)); } catch (Exception e) { return(Attempt <object> .Fail(e)); } } if (destinationType == typeof(bool)) { var boolConverter = new CustomBooleanTypeConverter(); if (boolConverter.CanConvertFrom(input.GetType())) { try { var converted = boolConverter.ConvertFrom(input); return(Attempt.Succeed(converted)); } catch (Exception e) { return(Attempt <object> .Fail(e)); } } } var outputConverter = TypeDescriptor.GetConverter(destinationType); if (outputConverter.CanConvertFrom(input.GetType())) { try { var converted = outputConverter.ConvertFrom(input); return(Attempt.Succeed(converted)); } catch (Exception e) { return(Attempt <object> .Fail(e)); } } if (TypeHelper.IsTypeAssignableFrom <IConvertible>(input)) { try { var casted = Convert.ChangeType(input, destinationType); return(Attempt.Succeed(casted)); } catch (Exception e) { return(Attempt <object> .Fail(e)); } } return(Attempt <object> .Fail()); }
/// <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 Attempt <object> TryConvertTo(this object input, Type destinationType) { if (input == null) { return(Attempt <object> .False); } if (destinationType == typeof(object)) { return(new Attempt <object>(true, input)); } if (input.GetType() == destinationType) { return(new Attempt <object>(true, input)); } if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable <>)) { //TODO: Do a check for destination type being IEnumerable<T> and source type implementing IEnumerable<T> with // the same 'T', then we'd have to find the extension method for the type AsEnumerable() and execute it. if (TypeHelper.IsTypeAssignableFrom(destinationType, input.GetType()) && TypeHelper.IsTypeAssignableFrom <IConvertible>(input)) { try { var casted = Convert.ChangeType(input, destinationType); return(new Attempt <object>(true, casted)); } catch (Exception e) { return(new Attempt <object>(e)); } } } var inputConverter = TypeDescriptor.GetConverter(input); if (inputConverter.CanConvertTo(destinationType)) { try { var converted = inputConverter.ConvertTo(input, destinationType); return(new Attempt <object>(true, converted)); } catch (Exception e) { return(new Attempt <object>(e)); } } if (destinationType == typeof(bool)) { var boolConverter = new CustomBooleanTypeConverter(); if (boolConverter.CanConvertFrom(input.GetType())) { try { var converted = boolConverter.ConvertFrom(input); return(new Attempt <object>(true, converted)); } catch (Exception e) { return(new Attempt <object>(e)); } } } var outputConverter = TypeDescriptor.GetConverter(destinationType); if (outputConverter.CanConvertFrom(input.GetType())) { try { var converted = outputConverter.ConvertFrom(input); return(new Attempt <object>(true, converted)); } catch (Exception e) { return(new Attempt <object>(e)); } } if (TypeHelper.IsTypeAssignableFrom <IConvertible>(input)) { try { var casted = Convert.ChangeType(input, destinationType); return(new Attempt <object>(true, casted)); } catch (Exception e) { return(new Attempt <object>(e)); } } return(Attempt <object> .False); }