Beispiel #1
0
 /// <summary>
 /// Creates a successful 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 successful attempt.</returns>
 public static Attempt <TResult, TStatus> SucceedWithStatus <TResult, TStatus>(TStatus status, TResult result)
 {
     return(Attempt <TResult, TStatus> .Succeed(status, result));
 }
Beispiel #2
0
        // note:
        // cannot rely on overloads only to differenciate between with/without status
        // in some cases it will always be ambiguous, so be explicit w/ 'WithStatus' methods

        /// <summary>
        /// Creates a successful 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 successful attempt.</returns>
        public static Attempt <TResult> Succeed <TResult>(TResult result)
        {
            return(Attempt <TResult> .Succeed(result));
        }
        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...
        }
        /// <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 it is null and it is nullable, then return success with null
            if (input == null && destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                return(Attempt <object> .Succeed(null));
            }

            //if its not nullable and it is a value type
            if (input == null && destinationType.IsValueType)
            {
                return(Attempt <object> .Fail());
            }
            //if the type can be null, then no problem
            if (input == null && destinationType.IsValueType == false)
            {
                return(Attempt <object> .Succeed(null));
            }

            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());
        }
Beispiel #5
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...
        }