Wie der int.TryParse tatsächlich funktioniert


78

Ich habe nach einer int.TryParseMethodenimplementierung gesucht , wie sie tatsächlich funktioniert, aber ich habe sie nicht gefunden. Ich muss über a wissen, stringob es sich um einen numerischen Wert handelt, aber ich möchte ihn derzeit nicht konvertieren.

Ich brauche also nur das boolErgebnis von int.TryParse. Die Fragen sind also:

  1. Gibt es eine Funktion, die nur das boolErgebnis liefern kann?

und

  1. Ich würde gerne wissen, wie das int.TryParsetatsächlich funktioniert (gibt es ein try ... catchInneres oder iteriert es durch die Zeichen der Eingabe string)?

1. Nein, gibt es nicht. Sie könnten verwenden Convert.ToInt32(), aber es wird eine Ausnahme auslösen, wenn die Zeichenfolge nicht analysiert werden kann. 2. Es muss durch die Zeichenfolge iterieren, aber es wird wahrscheinlich keine Ausnahme abfangen, da es schneller ist als die Ausnahme vonConvert.ToInt32()
Nolonar

Sie könnten Regex ^ \ d + $ verwenden. Oder werte jedes Zeichen für IsDigit aus.
Paparazzo

Antworten:


101

Wenn Sie nur das boolErgebnis benötigen , verwenden Sie einfach den Rückgabewert und ignorieren Sie den outParameter.

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

Bearbeiten : In der Zwischenzeit können Sie sich auch den Original-Quellcode ansehen :

System.Int32.TryParse


Wenn ich wissen möchte, wie etwas tatsächlich implementiert ist, ILSpydekompiliere ich den .NET-Code.

Das ist das Ergebnis:

// 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;
}

Und nein, ich kann keine Try-Catchsauf der Straße sehen:

// 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
Es ist komplexer als ich dachte :) Danke!
speti43

19

Nur weil int.TryParseSie den Wert erhalten, heißt das nicht, dass Sie ihn behalten müssen. Sie können dies ganz glücklich tun:

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

Sie können es tempvollständig ignorieren, wenn Sie es nicht benötigen. Wenn Sie es brauchen, dann wartet es auf Sie, wenn Sie es wollen.

Soweit ich mich erinnere, versucht die Interna, die Rohbytes der Zeichenfolge als int zu lesen, und prüft, ob das Ergebnis gültig ist oder so; Es ist nicht so einfach, durch die Suche nach nicht numerischen Zeichen zu iterieren.


15

Wir können jetzt in C # 7.0 und höher Folgendes schreiben:

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

Dies soll die Frage nicht beantworten.
Themenfeld

1
was macht out?
Mrid

@mrid Gibt an, dass dem Methodenbereich mit Schreibzugriff eine Variable im aufrufenden Bereich zugewiesen wird. Wenn beispielsweise eine Variable int someIntan int.TryParselike übergeben wird int.TryParse(out someInt), int.TryParsekann ihre Ausgabe in platziert werden someInt, obwohl sie normalerweise außerhalb des Gültigkeitsbereichs liegt.
Timelmer

@themefield - es beantwortet diese Frage direkt im Hauptteil des Beitrags: "Die Fragen sind also: 1) Gibt es eine Funktion, die nur das Bool-Ergebnis liefern kann?"
Antiduh

12

TryParse ist der beste Weg, um in einer Zeile zu analysieren oder zu validieren:

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

Kurze Beschreibung:

  1. nNumber wird mit Null initialisiert.
  2. int.TryParse () versucht, "InputString" zu analysieren und zu validieren, wenn dies erfolgreich ist, setzen Sie es auf nNumber.
  3. short if ?: Überprüfung des int.TryParse () - Ergebnisses, das nNumber oder 1 als Standardwert zurückgibt.

1
cannot use local variable 'nCurPage' before it is declared
Devin Burke

Lieber Devin-Burke, du hast Recht, aber es funktioniert. Ich benutze es mehrmals, ohne Fehler oder Warnung ...
Zolfaghari

8

Regex ist so kompiliert, dass Sie es aus Gründen der Geschwindigkeit einmal erstellen und wiederverwenden können.
Das neue dauert länger als das IsMatch.
Dies prüft nur auf alle Ziffern.
Die Reichweite wird nicht überprüft.
Wenn Sie die Reichweite testen müssen, ist TryParse der richtige Weg.

private static Regex regexInt = new Regex("^\\d+$");
static bool CheckReg(string value)
{
    return regexInt.IsMatch(value);
}

3

Überprüfen Sie dieses einfache Programm, um es zu verstehen int.TryParse

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

Ausgabe ist: 7788

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.