Beispiel #1
0
        /// <summary>
        /// Try to parse an IRange<T> from a string.
        /// Returns RangeResult<T> to avoid throwing an exception.
        public static RangeResult <T> GetResultFromString <T>(string value)
            where T : struct
        {
            var range = new Range <T>();

            /**
             * This expression is very cumbersome due to its requirement of handling
             * several formats. Please take note of the lookbehind assertion and its preceeding
             * word-boundary. The former lets us define a max-value using simple-syntax while
             * the latter accounts for the min-value (due to the assertion).
             * Valid formats (not exhaustive):
             * [123,456]
             * [123,
             * [123,456
             * 123
             * 123,456
             * 123,
             */
            var parsedValue = Regex.Match(
                value + ",",
                @"(?<startSyntax>[\[\(])?(?<minValue>[^,[(]+?)?(?:[\W])(?<=,)(?<maxValue>[^,\]\)]+)?(?<endSyntax>[\]\)])?");

            if (!parsedValue.Success)
            {
                return(RangeResult <T> .Error("value does not match expected format."));
            }
            else
            {
                var groups         = parsedValue.Groups;
                var parsedMinValue = groups["minValue"].Value;

                /**
                 * If we using short-range syntax, then we
                 * want to set the max-value if not provided.
                 */
                var parsedMaxValue =
                    string.IsNullOrEmpty(
                        groups["maxValue"].Value + groups["startSyntax"].Value + groups["endSyntax"].Value)
                    ? parsedMinValue
                    : groups["maxValue"].Value;

                var isMinInclusive =
                    (groups["startSyntax"].Value == "[" || string.IsNullOrEmpty(groups["startSyntax"].Value))
                    ? true
                    : false;
                var isMaxInclusive =
                    (groups["endSyntax"].Value == "]" || string.IsNullOrEmpty(groups["endSyntax"].Value))
                    ? true
                    : false;
                var isMinInfinite = parsedMinValue == "-∞" ? true : false;
                var isMaxInfinite = parsedMaxValue == "+∞" ? true : false;

                if (string.IsNullOrWhiteSpace(parsedMinValue) &&
                    string.IsNullOrWhiteSpace(parsedMaxValue))
                {
                    return(RangeResult <T> .Error("value cannot be open-ended for both min and max-values."));
                }

                if (isMinInclusive && isMinInfinite)
                {
                    return(RangeResult <T> .Error("value cannot have inclusive infinite lower-bound."));
                }

                if (isMaxInclusive && isMaxInfinite)
                {
                    return(RangeResult <T> .Error("value cannot have inclusive infinite upper-bound."));
                }

                T?minValue = default(T?);
                T?maxValue = default(T?);

                if (!string.IsNullOrWhiteSpace(parsedMinValue) && !isMinInfinite)
                {
                    try
                    {
                        minValue = SmartConverter.Convert <T>(
                            parsedMinValue,
                            isMinInclusive ? ConvertingKind.MinInclusive : ConvertingKind.MinExclusive
                            );
                    }
                    catch (Exception)
                    {
                        return(RangeResult <T> .Error(
                                   string.Format("parsed minimum value `{0}` does not match expected type of `{1}`.",
                                                 groups["minValue"].Value,
                                                 typeof(T).Name)));
                    }
                }

                if (!string.IsNullOrWhiteSpace(parsedMaxValue) && !isMaxInfinite)
                {
                    try
                    {
                        maxValue = SmartConverter.Convert <T>(parsedMaxValue,
                                                              isMaxInclusive ? ConvertingKind.MaxInclusive : ConvertingKind.MaxExclusive
                                                              );
                    }
                    catch (Exception)
                    {
                        return(RangeResult <T> .Error(
                                   string.Format("parsed maximum value `{0}` does not match expected type of `{1}`.",
                                                 groups["maxValue"].Value,
                                                 typeof(T).Name)));
                    }
                }

                range.MinValue       = minValue;
                range.MaxValue       = maxValue;
                range.IsMinInclusive = isMinInclusive;
                range.IsMaxInclusive = isMaxInclusive;
            }

            if (range.MinValue.HasValue && range.MaxValue.HasValue)
            {
                var anyInclusiveRanges = range.IsMinInclusive || range.IsMaxInclusive;
                var compareResult      = Comparer <T> .Default.Compare(range.MinValue.Value, range.MaxValue.Value);

                if (anyInclusiveRanges && compareResult > 0)
                {
                    return(RangeResult <T> .Error(
                               "Minimum value of range must be less than or equal to maximum value."));
                }

                if (!anyInclusiveRanges && compareResult >= 0)
                {
                    return(RangeResult <T> .Error(
                               "Minimum value of range must be less than maximum value when range is non-inclusive."));
                }
            }

            return(RangeResult <T> .Success(range));
        }