Как на самом деле работает int.TryParse

80

Я искал int.TryParseреализацию метода, как он работает на самом деле, но не нашел. Я должен знать, stringчисловое ли это значение, но сейчас я не хочу его преобразовывать.

Так что мне нужен только boolрезультат int.TryParse. Итак, вопросы:

  1. Есть ли функция, которая может дать только boolрезультат,

и

  1. Я хотел бы знать, как на int.TryParseсамом деле работает (есть ли try ... catchвнутри или перебирает символы ввода string)?
speti43
источник
1. Нет, нет. Вы можете использовать Convert.ToInt32(), но это вызовет исключение, если строка не может быть проанализирована. 2. Ему придется перебирать строку, но, вероятно, он не поймает никаких исключений, так как это быстрее, чем Convert.ToInt32()
перехватить
Вы можете использовать регулярное выражение ^ \ d + $. Или оцените каждый символ для IsDigit.
папараццо

Ответы:

103

Если вам нужен только boolрезультат, просто используйте возвращаемое значение и игнорируйте outпараметр.

bool successfullyParsed = int.TryParse(str, out ignoreMe);
if (successfullyParsed){
    // ...
}

Изменить : Между тем вы также можете посмотреть исходный исходный код :

System.Int32.TryParse


Если я хочу знать, как что-то на самом деле реализовано, я использую ILSpyдля декомпиляции .NET-кода.

Вот результат:

// int
/// <summary>Converts the string representation of a number to its 32-bit signed integer equivalent. A return value indicates whether the operation succeeded.</summary>
/// <returns>true if s was converted successfully; otherwise, false.</returns>
/// <param name="s">A string containing a number to convert. </param>
/// <param name="result">When this method returns, contains the 32-bit signed integer value equivalent to the number contained in s, if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null, is not of the correct format, or represents a number less than <see cref="F:System.Int32.MinValue"></see> or greater than <see cref="F:System.Int32.MaxValue"></see>. This parameter is passed uninitialized. </param>
/// <filterpriority>1</filterpriority>
public static bool TryParse(string s, out int result)
{
    return Number.TryParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
}


// System.Number
internal unsafe static bool TryParseInt32(string s, NumberStyles style, NumberFormatInfo info, out int result)
{
    byte* stackBuffer = stackalloc byte[1 * 114 / 1];
    Number.NumberBuffer numberBuffer = new Number.NumberBuffer(stackBuffer);
    result = 0;
    if (!Number.TryStringToNumber(s, style, ref numberBuffer, info, false))
    {
        return false;
    }
    if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
    {
        if (!Number.HexNumberToInt32(ref numberBuffer, ref result))
        {
            return false;
        }
    }
    else
    {
        if (!Number.NumberToInt32(ref numberBuffer, ref result))
        {
            return false;
        }
    }
    return true;
}

И нет, Try-Catchsна дороге ничего не вижу :

// System.Number
private unsafe static bool TryStringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
{
    if (str == null)
    {
        return false;
    }
    fixed (char* ptr = str)
    {
        char* ptr2 = ptr;
        if (!Number.ParseNumber(ref ptr2, options, ref number, numfmt, parseDecimal) || ((ptr2 - ptr / 2) / 2 < str.Length && !Number.TrailingZeros(str, (ptr2 - ptr / 2) / 2)))
        {
            return false;
        }
    }
    return true;
}

// System.Number
private unsafe static bool ParseNumber(ref char* str, NumberStyles options, ref Number.NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
{
    number.scale = 0;
    number.sign = false;
    string text = null;
    string text2 = null;
    string str2 = null;
    string str3 = null;
    bool flag = false;
    string str4;
    string str5;
    if ((options & NumberStyles.AllowCurrencySymbol) != NumberStyles.None)
    {
        text = numfmt.CurrencySymbol;
        if (numfmt.ansiCurrencySymbol != null)
        {
            text2 = numfmt.ansiCurrencySymbol;
        }
        str2 = numfmt.NumberDecimalSeparator;
        str3 = numfmt.NumberGroupSeparator;
        str4 = numfmt.CurrencyDecimalSeparator;
        str5 = numfmt.CurrencyGroupSeparator;
        flag = true;
    }
    else
    {
        str4 = numfmt.NumberDecimalSeparator;
        str5 = numfmt.NumberGroupSeparator;
    }
    int num = 0;
    char* ptr = str;
    char c = *ptr;
    while (true)
    {
        if (!Number.IsWhite(c) || (options & NumberStyles.AllowLeadingWhite) == NumberStyles.None || ((num & 1) != 0 && ((num & 1) == 0 || ((num & 32) == 0 && numfmt.numberNegativePattern != 2))))
        {
            bool flag2;
            char* ptr2;
            if ((flag2 = ((options & NumberStyles.AllowLeadingSign) != NumberStyles.None && (num & 1) == 0)) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
            {
                num |= 1;
                ptr = ptr2 - (IntPtr)2 / 2;
            }
            else
            {
                if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                {
                    num |= 1;
                    number.sign = true;
                    ptr = ptr2 - (IntPtr)2 / 2;
                }
                else
                {
                    if (c == '(' && (options & NumberStyles.AllowParentheses) != NumberStyles.None && (num & 1) == 0)
                    {
                        num |= 3;
                        number.sign = true;
                    }
                    else
                    {
                        if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                        {
                            break;
                        }
                        num |= 32;
                        text = null;
                        text2 = null;
                        ptr = ptr2 - (IntPtr)2 / 2;
                    }
                }
            }
        }
        c = *(ptr += (IntPtr)2 / 2);
    }
    int num2 = 0;
    int num3 = 0;
    while (true)
    {
        if ((c >= '0' && c <= '9') || ((options & NumberStyles.AllowHexSpecifier) != NumberStyles.None && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))))
        {
            num |= 4;
            if (c != '0' || (num & 8) != 0)
            {
                if (num2 < 50)
                {
                    number.digits[(IntPtr)(num2++)] = c;
                    if (c != '0' || parseDecimal)
                    {
                        num3 = num2;
                    }
                }
                if ((num & 16) == 0)
                {
                    number.scale++;
                }
                num |= 8;
            }
            else
            {
                if ((num & 16) != 0)
                {
                    number.scale--;
                }
            }
        }
        else
        {
            char* ptr2;
            if ((options & NumberStyles.AllowDecimalPoint) != NumberStyles.None && (num & 16) == 0 && ((ptr2 = Number.MatchChars(ptr, str4)) != null || (flag && (num & 32) == 0 && (ptr2 = Number.MatchChars(ptr, str2)) != null)))
            {
                num |= 16;
                ptr = ptr2 - (IntPtr)2 / 2;
            }
            else
            {
                if ((options & NumberStyles.AllowThousands) == NumberStyles.None || (num & 4) == 0 || (num & 16) != 0 || ((ptr2 = Number.MatchChars(ptr, str5)) == null && (!flag || (num & 32) != 0 || (ptr2 = Number.MatchChars(ptr, str3)) == null)))
                {
                    break;
                }
                ptr = ptr2 - (IntPtr)2 / 2;
            }
        }
        c = *(ptr += (IntPtr)2 / 2);
    }
    bool flag3 = false;
    number.precision = num3;
    number.digits[(IntPtr)num3] = '\0';
    if ((num & 4) != 0)
    {
        if ((c == 'E' || c == 'e') && (options & NumberStyles.AllowExponent) != NumberStyles.None)
        {
            char* ptr3 = ptr;
            c = *(ptr += (IntPtr)2 / 2);
            char* ptr2;
            if ((ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
            {
                c = *(ptr = ptr2);
            }
            else
            {
                if ((ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                {
                    c = *(ptr = ptr2);
                    flag3 = true;
                }
            }
            if (c >= '0' && c <= '9')
            {
                int num4 = 0;
                do
                {
                    num4 = num4 * 10 + (int)(c - '0');
                    c = *(ptr += (IntPtr)2 / 2);
                    if (num4 > 1000)
                    {
                        num4 = 9999;
                        while (c >= '0' && c <= '9')
                        {
                            c = *(ptr += (IntPtr)2 / 2);
                        }
                    }
                }
                while (c >= '0' && c <= '9');
                if (flag3)
                {
                    num4 = -num4;
                }
                number.scale += num4;
            }
            else
            {
                ptr = ptr3;
                c = *ptr;
            }
        }
        while (true)
        {
            if (!Number.IsWhite(c) || (options & NumberStyles.AllowTrailingWhite) == NumberStyles.None)
            {
                bool flag2;
                char* ptr2;
                if ((flag2 = ((options & NumberStyles.AllowTrailingSign) != NumberStyles.None && (num & 1) == 0)) && (ptr2 = Number.MatchChars(ptr, numfmt.positiveSign)) != null)
                {
                    num |= 1;
                    ptr = ptr2 - (IntPtr)2 / 2;
                }
                else
                {
                    if (flag2 && (ptr2 = Number.MatchChars(ptr, numfmt.negativeSign)) != null)
                    {
                        num |= 1;
                        number.sign = true;
                        ptr = ptr2 - (IntPtr)2 / 2;
                    }
                    else
                    {
                        if (c == ')' && (num & 2) != 0)
                        {
                            num &= -3;
                        }
                        else
                        {
                            if ((text == null || (ptr2 = Number.MatchChars(ptr, text)) == null) && (text2 == null || (ptr2 = Number.MatchChars(ptr, text2)) == null))
                            {
                                break;
                            }
                            text = null;
                            text2 = null;
                            ptr = ptr2 - (IntPtr)2 / 2;
                        }
                    }
                }
            }
            c = *(ptr += (IntPtr)2 / 2);
        }
        if ((num & 2) == 0)
        {
            if ((num & 8) == 0)
            {
                if (!parseDecimal)
                {
                    number.scale = 0;
                }
                if ((num & 16) == 0)
                {
                    number.sign = false;
                }
            }
            str = ptr;
            return true;
        }
    }
    str = ptr;
    return false;
}
Тим Шмельтер
источник
4
Это сложнее, чем я думал :) Спасибо!
speti43 08
19

Просто потому, что int.TryParseдает вам ценность, не означает, что вам нужно ее сохранить; вы вполне можете сделать это:

int temp;
if (int.TryParse(inputString, out temp))
{
    // do stuff
}

Вы можете tempполностью игнорировать, если вам это не нужно. Если он вам действительно нужен, то он ждет вас, когда вы этого захотите.

Что касается внутреннего устройства, насколько я помню, он пытается прочитать необработанные байты строки как int и проверяет, верен ли результат или что-то в этом роде; это не так просто, как итерация путем поиска нечисловых символов.

анаксимандр
источник
16

Теперь в C # 7.0 и выше мы можем написать следующее:

if (int.TryParse(inputString, out _))
{
    //do stuff
}
RFE Петр
источник
Это не для ответа на вопрос.
themefield
1
что делать?
мд
@mrid Он указывает, что переменная в вызывающей области передается в область метода с доступом на запись. Например, если переменная int someIntпередается в int.TryParselike int.TryParse(out someInt), int.TryParseможет помещать ее вывод someInt, даже если обычно он находится вне области видимости.
timelmer
@themefield - он отвечает на этот вопрос прямо в теле сообщения: «Итак, вопросы: 1) Есть ли какая-либо функция, которая может предоставить только результат типа bool».
antiduh 04
13

TryParse - лучший способ синтаксического анализа или проверки в одной строке:

int nNumber = int.TryParse("InputString", out nNumber) ? nNumber : 1;

Краткое описание:

  1. nNumber инициализируется нулем,
  2. int.TryParse () попробуйте проанализировать "InputString" и проверить его, если успешно установлено в nNumber.
  3. short if?: проверка результата int.TryParse (), которая возвращает nNumber или 1 в качестве значения по умолчанию.
Золфагари
источник
1
cannot use local variable 'nCurPage' before it is declared
Девин Берк
дорогой Девин-Берк, ты прав, но это работает. Я использую его несколько раз, без каких-либо ошибок или предупреждений ...
Золфагари
8

Regex скомпилирован, поэтому для ускорения создайте его один раз и используйте повторно.
Новое занимает больше времени, чем IsMatch.
Это проверяет только все цифры.
Он не проверяет диапазон.
Если вам нужно проверить диапазон, попробуйте TryParse.

private static Regex regexInt = new Regex("^\\d+$");
static bool CheckReg(string value)
{
    return regexInt.IsMatch(value);
}
папарацци
источник
2

Проверьте эту простую программу, чтобы понять int.TryParse

 class Program
 {
    static void Main()
    {
        string str = "7788";
        int num1;
        bool n = int.TryParse(str, out num1);
        Console.WriteLine(num1);
        Console.ReadLine();
    }
}

Выход: 7788

Сайед
источник