示例#1
0
        private static Nullable <Attempt <object> > TryConvertToFromString(this string input, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                return(Attempt <object> .Succeed(input));
            }

            if (string.IsNullOrEmpty(input))
            {
                if (destinationType == typeof(Boolean))
                {
                    return(Attempt <object> .Succeed(false));                    // special case for booleans, null/empty == false
                }
                if (destinationType == typeof(DateTime))
                {
                    return(Attempt <object> .Succeed(DateTime.MinValue));
                }
            }

            // we have a non-empty string, look for type conversions in the expected order of frequency of use...
            if (destinationType.IsPrimitive)
            {
                if (destinationType == typeof(Int32))
                {
                    Int32 value;
                    return(Int32.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                if (destinationType == typeof(Int64))
                {
                    Int64 value;
                    return(Int64.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                if (destinationType == typeof(Boolean))
                {
                    Boolean value;
                    if (Boolean.TryParse(input, out value))
                    {
                        return(Attempt <object> .Succeed(value));           // don't declare failure so the CustomBooleanTypeConverter can try
                    }
                }
                else if (destinationType == typeof(Int16))
                {
                    Int16 value;
                    return(Int16.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Double))
                {
                    Double value;
                    return(Double.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Single))
                {
                    Single value;
                    return(Single.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Char))
                {
                    Char value;
                    return(Char.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Byte))
                {
                    Byte value;
                    return(Byte.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(SByte))
                {
                    SByte value;
                    return(SByte.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(UInt32))
                {
                    UInt32 value;
                    return(UInt32.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(UInt16))
                {
                    UInt16 value;
                    return(UInt16.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(UInt64))
                {
                    UInt64 value;
                    return(UInt64.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
            }
            else if (destinationType == typeof(Guid))
            {
                Guid value;
                return(Guid.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(DateTime))
            {
                DateTime value;
                return(DateTime.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(DateTimeOffset))
            {
                DateTimeOffset value;
                return(DateTimeOffset.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(TimeSpan))
            {
                TimeSpan value;
                return(TimeSpan.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(Decimal))
            {
                Decimal value;
                return(Decimal.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(Version))
            {
                Version value;
                return(Version.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            // E_NOTIMPL IPAddress, BigInteger

            return(null);            // we can't decide...
        }
示例#2
0
        /// <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>
        /// 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>
        /// Attempts to convert the input string 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="Nullable{Attempt}"/></returns>
        private static Attempt <object>?TryConvertToFromString(this string input, Type target)
        {
            // Easy
            if (target == typeof(string))
            {
                return(Attempt <object> .Succeed(input));
            }

            // Null, empty, whitespaces
            if (string.IsNullOrWhiteSpace(input))
            {
                if (target == typeof(bool))
                {
                    // null/empty = bool false
                    return(Attempt <object> .Succeed(false));
                }

                if (target == typeof(DateTime))
                {
                    // null/empty = min DateTime value
                    return(Attempt <object> .Succeed(DateTime.MinValue));
                }

                // Cannot decide here,
                // Any of the types below will fail parsing and will return a failed attempt
                // but anything else will not be processed and will return null
                // so even though the string is null/empty we have to proceed.
            }

            // Look for type conversions in the expected order of frequency of use.
            //
            // By using a mixture of ordered if statements and switches we can optimize both for
            // fast conditional checking for most frequently used types and the branching
            // that does not depend on previous values available to switch statements.
            if (target.IsPrimitive)
            {
                if (target == typeof(int))
                {
                    if (int.TryParse(input, out var value))
                    {
                        return(Attempt <object> .Succeed(value));
                    }

                    // Because decimal 100.01m will happily convert to integer 100, it
                    // makes sense that string "100.01" *also* converts to integer 100.
                    var input2 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2)));
                }

                if (target == typeof(long))
                {
                    if (long.TryParse(input, out var value))
                    {
                        return(Attempt <object> .Succeed(value));
                    }

                    // Same as int
                    var input2 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2)));
                }

                // TODO: Should we do the decimal trick for short, byte, unsigned?

                if (target == typeof(bool))
                {
                    if (bool.TryParse(input, out var value))
                    {
                        return(Attempt <object> .Succeed(value));
                    }

                    // Don't declare failure so the CustomBooleanTypeConverter can try
                    return(null);
                }

                // Calling this method directly is faster than any attempt to cache it.
                switch (Type.GetTypeCode(target))
                {
                case TypeCode.Int16:
                    return(Attempt <object> .SucceedIf(short.TryParse(input, out var value), value));

                case TypeCode.Double:
                    var input2 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(double.TryParse(input2, out var valueD), valueD));

                case TypeCode.Single:
                    var input3 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(float.TryParse(input3, out var valueF), valueF));

                case TypeCode.Char:
                    return(Attempt <object> .SucceedIf(char.TryParse(input, out var valueC), valueC));

                case TypeCode.Byte:
                    return(Attempt <object> .SucceedIf(byte.TryParse(input, out var valueB), valueB));

                case TypeCode.SByte:
                    return(Attempt <object> .SucceedIf(sbyte.TryParse(input, out var valueSb), valueSb));

                case TypeCode.UInt32:
                    return(Attempt <object> .SucceedIf(uint.TryParse(input, out var valueU), valueU));

                case TypeCode.UInt16:
                    return(Attempt <object> .SucceedIf(ushort.TryParse(input, out var valueUs), valueUs));

                case TypeCode.UInt64:
                    return(Attempt <object> .SucceedIf(ulong.TryParse(input, out var valueUl), valueUl));
                }
            }
            else if (target == typeof(Guid))
            {
                return(Attempt <object> .SucceedIf(Guid.TryParse(input, out var value), value));
            }
            else if (target == typeof(DateTime))
            {
                if (DateTime.TryParse(input, out var value))
                {
                    switch (value.Kind)
                    {
                    case DateTimeKind.Unspecified:
                    case DateTimeKind.Utc:
                        return(Attempt <object> .Succeed(value));

                    case DateTimeKind.Local:
                        return(Attempt <object> .Succeed(value.ToUniversalTime()));

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }

                return(Attempt <object> .Fail());
            }
            else if (target == typeof(DateTimeOffset))
            {
                return(Attempt <object> .SucceedIf(DateTimeOffset.TryParse(input, out var value), value));
            }
            else if (target == typeof(TimeSpan))
            {
                return(Attempt <object> .SucceedIf(TimeSpan.TryParse(input, out var value), value));
            }
            else if (target == typeof(decimal))
            {
                var input2 = NormalizeNumberDecimalSeparator(input);
                return(Attempt <object> .SucceedIf(decimal.TryParse(input2, out var value), value));
            }
            else if (input != null && target == typeof(Version))
            {
                return(Attempt <object> .SucceedIf(Version.TryParse(input, out var value), value));
            }

            // E_NOTIMPL IPAddress, BigInteger
            return(null); // We can't decide...
        }
示例#5
0
 /// <summary>
 /// Creates a failed attempt with a result and an exception.
 /// </summary>
 /// <typeparam name="TResult">The type of the attempted operation result.</typeparam>
 /// <param name="result">The result of the attempt.</param>
 /// <param name="exception">The exception causing the failure of the attempt.</param>
 /// <returns>The failed attempt.</returns>
 public static Attempt <TResult> Fail <TResult>(TResult result, Exception exception)
 {
     return(Attempt <TResult> .Fail(result, exception));
 }
示例#6
0
 /// <summary>
 /// Creates a failed attempt with a result, an exception and a status.
 /// </summary>
 /// <typeparam name="TResult">The type of the attempted operation result.</typeparam>
 /// <typeparam name="TStatus">The type of the attempted operation status.</typeparam>
 /// <param name="status">The status of the attempt.</param>
 /// <param name="result">The result of the attempt.</param>
 /// <param name="exception">The exception causing the failure of the attempt.</param>
 /// <returns>The failed attempt.</returns>
 public static Attempt <TResult, TStatus> FailWithStatus <TResult, TStatus>(TStatus status, TResult result, Exception exception)
 {
     return(Attempt <TResult, TStatus> .Fail(status, result, exception));
 }
示例#7
0
 /// <summary>
 /// Creates a failed attempt with a result and a status.
 /// </summary>
 /// <typeparam name="TResult">The type of the attempted operation result.</typeparam>
 /// <typeparam name="TStatus">The type of the attempted operation status.</typeparam>
 /// <param name="status">The status of the attempt.</param>
 /// <param name="result">The result of the attempt.</param>
 /// <returns>The failed attempt.</returns>
 public static Attempt <TResult, TStatus> FailWithStatus <TResult, TStatus>(TStatus status, TResult result)
 {
     return(Attempt <TResult, TStatus> .Fail(status, result));
 }
示例#8
0
 /// <summary>
 /// Creates a failed attempt with a result.
 /// </summary>
 /// <typeparam name="TResult">The type of the attempted operation result.</typeparam>
 /// <param name="result">The result of the attempt.</param>
 /// <returns>The failed attempt.</returns>
 public static Attempt <TResult> Fail <TResult>(TResult result)
 {
     return(Attempt <TResult> .Fail(result));
 }
示例#9
0
 /// <summary>
 /// Creates a failed attempt.
 /// </summary>
 /// <typeparam name="TResult">The type of the attempted operation result.</typeparam>
 /// <returns>The failed attempt.</returns>
 public static Attempt <TResult> Fail <TResult>()
 {
     return(Attempt <TResult> .Fail());
 }
        private static Nullable <Attempt <object> > TryConvertToFromString(this string input, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                return(Attempt <object> .Succeed(input));
            }

            if (string.IsNullOrEmpty(input))
            {
                if (destinationType == typeof(Boolean))
                {
                    return(Attempt <object> .Succeed(false));                    // special case for booleans, null/empty == false
                }
                if (destinationType == typeof(DateTime))
                {
                    return(Attempt <object> .Succeed(DateTime.MinValue));
                }
            }

            // we have a non-empty string, look for type conversions in the expected order of frequency of use...
            if (destinationType.IsPrimitive)
            {
                if (destinationType == typeof(Int32))
                {
                    Int32 value;
                    return(Int32.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                if (destinationType == typeof(Int64))
                {
                    Int64 value;
                    return(Int64.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                if (destinationType == typeof(Boolean))
                {
                    Boolean value;
                    if (Boolean.TryParse(input, out value))
                    {
                        return(Attempt <object> .Succeed(value));           // don't declare failure so the CustomBooleanTypeConverter can try
                    }
                }
                else if (destinationType == typeof(Int16))
                {
                    Int16 value;
                    return(Int16.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Double))
                {
                    Double value;
                    var    input2 = NormalizeNumberDecimalSeparator(input);
                    return(Double.TryParse(input2, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Single))
                {
                    Single value;
                    var    input2 = NormalizeNumberDecimalSeparator(input);
                    return(Single.TryParse(input2, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Char))
                {
                    Char value;
                    return(Char.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(Byte))
                {
                    Byte value;
                    return(Byte.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(SByte))
                {
                    SByte value;
                    return(SByte.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(UInt32))
                {
                    UInt32 value;
                    return(UInt32.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(UInt16))
                {
                    UInt16 value;
                    return(UInt16.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
                else if (destinationType == typeof(UInt64))
                {
                    UInt64 value;
                    return(UInt64.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
                }
            }
            else if (destinationType == typeof(Guid))
            {
                Guid value;
                return(Guid.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(DateTime))
            {
                DateTime value;
                if (DateTime.TryParse(input, out value))
                {
                    switch (value.Kind)
                    {
                    case DateTimeKind.Unspecified:
                    case DateTimeKind.Utc:
                        return(Attempt <object> .Succeed(value));

                    case DateTimeKind.Local:
                        return(Attempt <object> .Succeed(value.ToUniversalTime()));

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
                return(Attempt <object> .Fail());
            }
            else if (destinationType == typeof(DateTimeOffset))
            {
                DateTimeOffset value;
                return(DateTimeOffset.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(TimeSpan))
            {
                TimeSpan value;
                return(TimeSpan.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(Decimal))
            {
                Decimal value;
                var     input2 = NormalizeNumberDecimalSeparator(input);
                return(Decimal.TryParse(input2, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            else if (destinationType == typeof(Version))
            {
                Version value;
                return(Version.TryParse(input, out value) ? Attempt <object> .Succeed(value) : Attempt <object> .Fail());
            }
            // E_NOTIMPL IPAddress, BigInteger

            return(null);            // we can't decide...
        }
示例#11
0
        // returns an attempt if the string has been processed (either succeeded or failed)
        // returns null if we need to try other methods
        private static Attempt <object>?TryConvertToFromString(this string input, Type destinationType)
        {
            // easy
            if (destinationType == typeof(string))
            {
                return(Attempt <object> .Succeed(input));
            }

            // null, empty, whitespaces
            if (string.IsNullOrWhiteSpace(input))
            {
                if (destinationType == typeof(bool))                 // null/empty = bool false
                {
                    return(Attempt <object> .Succeed(false));
                }
                if (destinationType == typeof(DateTime))                 // null/empty = min DateTime value
                {
                    return(Attempt <object> .Succeed(DateTime.MinValue));
                }

                // cannot decide here,
                // any of the types below will fail parsing and will return a failed attempt
                // but anything else will not be processed and will return null
                // so even though the string is null/empty we have to proceed
            }

            // look for type conversions in the expected order of frequency of use...
            if (destinationType.IsPrimitive)
            {
                if (destinationType == typeof(int))             // aka Int32
                {
                    int value;
                    if (int.TryParse(input, out value))
                    {
                        return(Attempt <object> .Succeed(value));
                    }

                    // because decimal 100.01m will happily convert to integer 100, it
                    // makes sense that string "100.01" *also* converts to integer 100.
                    decimal value2;
                    var     input2 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt32(value2)));
                }

                if (destinationType == typeof(long)) // aka Int64
                {
                    long value;
                    if (long.TryParse(input, out value))
                    {
                        return(Attempt <object> .Succeed(value));
                    }

                    // same as int
                    decimal value2;
                    var     input2 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt64(value2)));
                }

                // fixme - should we do the decimal trick for short, byte, unsigned?

                if (destinationType == typeof(bool))             // aka Boolean
                {
                    bool value;
                    if (bool.TryParse(input, out value))
                    {
                        return(Attempt <object> .Succeed(value));
                    }
                    // don't declare failure so the CustomBooleanTypeConverter can try
                    return(null);
                }

                if (destinationType == typeof(short))             // aka Int16
                {
                    short value;
                    return(Attempt <object> .SucceedIf(short.TryParse(input, out value), value));
                }

                if (destinationType == typeof(double))             // aka Double
                {
                    double value;
                    var    input2 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(double.TryParse(input2, out value), value));
                }

                if (destinationType == typeof(float))             // aka Single
                {
                    float value;
                    var   input2 = NormalizeNumberDecimalSeparator(input);
                    return(Attempt <object> .SucceedIf(float.TryParse(input2, out value), value));
                }

                if (destinationType == typeof(char))             // aka Char
                {
                    char value;
                    return(Attempt <object> .SucceedIf(char.TryParse(input, out value), value));
                }

                if (destinationType == typeof(byte))             // aka Byte
                {
                    byte value;
                    return(Attempt <object> .SucceedIf(byte.TryParse(input, out value), value));
                }

                if (destinationType == typeof(sbyte))             // aka SByte
                {
                    sbyte value;
                    return(Attempt <object> .SucceedIf(sbyte.TryParse(input, out value), value));
                }

                if (destinationType == typeof(uint))             // aka UInt32
                {
                    uint value;
                    return(Attempt <object> .SucceedIf(uint.TryParse(input, out value), value));
                }

                if (destinationType == typeof(ushort))             // aka UInt16
                {
                    ushort value;
                    return(Attempt <object> .SucceedIf(ushort.TryParse(input, out value), value));
                }

                if (destinationType == typeof(ulong))             // aka UInt64
                {
                    ulong value;
                    return(Attempt <object> .SucceedIf(ulong.TryParse(input, out value), value));
                }
            }
            else if (destinationType == typeof(Guid))
            {
                Guid value;
                return(Attempt <object> .SucceedIf(Guid.TryParse(input, out value), value));
            }
            else if (destinationType == typeof(DateTime))
            {
                DateTime value;
                if (DateTime.TryParse(input, out value))
                {
                    switch (value.Kind)
                    {
                    case DateTimeKind.Unspecified:
                    case DateTimeKind.Utc:
                        return(Attempt <object> .Succeed(value));

                    case DateTimeKind.Local:
                        return(Attempt <object> .Succeed(value.ToUniversalTime()));

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
                return(Attempt <object> .Fail());
            }
            else if (destinationType == typeof(DateTimeOffset))
            {
                DateTimeOffset value;
                return(Attempt <object> .SucceedIf(DateTimeOffset.TryParse(input, out value), value));
            }
            else if (destinationType == typeof(TimeSpan))
            {
                TimeSpan value;
                return(Attempt <object> .SucceedIf(TimeSpan.TryParse(input, out value), value));
            }
            else if (destinationType == typeof(decimal))             // aka Decimal
            {
                decimal value;
                var     input2 = NormalizeNumberDecimalSeparator(input);
                return(Attempt <object> .SucceedIf(decimal.TryParse(input2, out value), value));
            }
            else if (destinationType == typeof(Version))
            {
                Version value;
                return(Attempt <object> .SucceedIf(Version.TryParse(input, out value), value));
            }
            // E_NOTIMPL IPAddress, BigInteger

            return(null);            // we can't decide...
        }