Exemple #1
0
        public static object ParseEnum(Type enumType, string value, bool disallowNumber)
        {
            ValidationUtils.ArgumentNotNull(enumType, nameof(enumType));
            ValidationUtils.ArgumentNotNull(value, nameof(value));

            if (!enumType.IsEnum())
            {
                throw new ArgumentException("Type provided must be an Enum.", nameof(enumType));
            }

            EnumInfo entry = ValuesAndNamesPerEnum.Get(enumType);

            string[] enumNames     = entry.Names;
            string[] resolvedNames = entry.ResolvedNames;
            ulong[]  enumValues    = entry.Values;

            // first check if the entire text (including commas) matches a resolved name
            int?matchingIndex = FindIndexByName(resolvedNames, value, 0, value.Length, StringComparison.Ordinal);

            if (matchingIndex != null)
            {
                return(Enum.ToObject(enumType, enumValues[matchingIndex.Value]));
            }

            int firstNonWhitespaceIndex = -1;

            for (int i = 0; i < value.Length; i++)
            {
                if (!char.IsWhiteSpace(value[i]))
                {
                    firstNonWhitespaceIndex = i;
                    break;
                }
            }
            if (firstNonWhitespaceIndex == -1)
            {
                throw new ArgumentException("Must specify valid information for parsing in the string.");
            }

            // check whether string is a number and parse as a number value
            char firstNonWhitespaceChar = value[firstNonWhitespaceIndex];

            if (char.IsDigit(firstNonWhitespaceChar) || firstNonWhitespaceChar == '-' || firstNonWhitespaceChar == '+')
            {
                Type underlyingType = Enum.GetUnderlyingType(enumType);

                value = value.Trim();
                object temp = null;

                try
                {
                    temp = Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture);
                }
                catch (FormatException)
                {
                    // We need to Parse this as a String instead. There are cases
                    // when you tlbimp enums that can have values of the form "3D".
                    // Don't fix this code.
                }

                if (temp != null)
                {
                    if (disallowNumber)
                    {
                        throw new FormatException("Integer string '{0}' is not allowed.".FormatWith(CultureInfo.InvariantCulture, value));
                    }

                    return(Enum.ToObject(enumType, temp));
                }
            }

            ulong result = 0;

            int valueIndex = firstNonWhitespaceIndex;

            while (valueIndex <= value.Length) // '=' is to handle invalid case of an ending comma
            {
                // Find the next separator, if there is one, otherwise the end of the string.
                int endIndex = value.IndexOf(EnumSeparatorChar, valueIndex);
                if (endIndex == -1)
                {
                    endIndex = value.Length;
                }

                // Shift the starting and ending indices to eliminate whitespace
                int endIndexNoWhitespace = endIndex;
                while (valueIndex < endIndex && char.IsWhiteSpace(value[valueIndex]))
                {
                    valueIndex++;
                }

                while (endIndexNoWhitespace > valueIndex && char.IsWhiteSpace(value[endIndexNoWhitespace - 1]))
                {
                    endIndexNoWhitespace--;
                }
                int valueSubstringLength = endIndexNoWhitespace - valueIndex;

                // match with case sensitivity
                matchingIndex = MatchName(value, enumNames, resolvedNames, valueIndex, valueSubstringLength, StringComparison.Ordinal);

                // if no match found, attempt case insensitive search
                if (matchingIndex == null)
                {
                    matchingIndex = MatchName(value, enumNames, resolvedNames, valueIndex, valueSubstringLength, StringComparison.OrdinalIgnoreCase);
                }

                if (matchingIndex == null)
                {
                    // still can't find a match
                    // before we throw an error, check whether the entire string has a case insensitive match against resolve names
                    matchingIndex = FindIndexByName(resolvedNames, value, 0, value.Length, StringComparison.OrdinalIgnoreCase);
                    if (matchingIndex != null)
                    {
                        return(Enum.ToObject(enumType, enumValues[matchingIndex.Value]));
                    }

                    // no match so error
                    throw new ArgumentException("Requested value '{0}' was not found.".FormatWith(CultureInfo.InvariantCulture, value));
                }

                result |= enumValues[matchingIndex.Value];

                // Move our pointer to the ending index to go again.
                valueIndex = endIndex + 1;
            }

            return(Enum.ToObject(enumType, result));
        }
Exemple #2
0
        private static String InternalFlagsFormat(EnumInfo entry, ulong result, bool camelCaseText)
        {
            string[] resolvedNames = entry.ResolvedNames;
            ulong[]  values        = entry.Values;

            int           index      = values.Length - 1;
            StringBuilder sb         = new StringBuilder();
            bool          firstTime  = true;
            ulong         saveResult = result;

            // We will not optimize this code further to keep it maintainable. There are some boundary checks that can be applied
            // to minimize the comparsions required. This code works the same for the best/worst case. In general the number of
            // items in an enum are sufficiently small and not worth the optimization.
            while (index >= 0)
            {
                if (index == 0 && values[index] == 0)
                {
                    break;
                }

                if ((result & values[index]) == values[index])
                {
                    result -= values[index];
                    if (!firstTime)
                    {
                        sb.Insert(0, EnumSeparatorString);
                    }

                    string resolvedName = resolvedNames[index];
                    sb.Insert(0, camelCaseText ? StringUtils.ToCamelCase(resolvedName) : resolvedName);
                    firstTime = false;
                }

                index--;
            }

            string returnString;

            if (result != 0)
            {
                // We were unable to represent this number as a bitwise or of valid flags
                returnString = null; // return null so the caller knows to .ToString() the input
            }
            else if (saveResult == 0)
            {
                // For the cases when we have zero
                if (values.Length > 0 && values[0] == 0)
                {
                    returnString = resolvedNames[0]; // Zero was one of the enum values.
                    if (camelCaseText)
                    {
                        returnString = StringUtils.ToCamelCase(returnString);
                    }
                }
                else
                {
                    returnString = null;
                }
            }
            else
            {
                returnString = sb.ToString(); // Return the string representation
            }

            return(returnString);
        }