Cách int.TryParse thực sự hoạt động


80

Tôi đã tìm cách int.TryParsetriển khai phương pháp, nó thực sự hoạt động như thế nào, nhưng tôi chưa tìm thấy. Tôi phải biết, về a string, cho dù đó là giá trị số, nhưng tôi không muốn chuyển đổi nó vào lúc này.

Vì vậy, tôi chỉ cần boolkết quả từ int.TryParse. Vì vậy, các câu hỏi là:

  1. Có bất kỳ chức năng nào chỉ có thể cung cấp boolkết quả,

và

  1. Tôi muốn biết, cách int.TryParsethực sự hoạt động (có try ... catchbên trong hoặc lặp lại qua các ký tự của đầu vào string)?

1. Không, không có. Bạn có thể sử dụng Convert.ToInt32(), nhưng nó sẽ ném ra một ngoại lệ, nếu chuỗi không thể được phân tích cú pháp. 2. Nó sẽ phải lặp qua chuỗi, nhưng nó có lẽ sẽ không bắt bất kỳ ngoại lệ, vì nó nhanh hơn so với đánh bắt các ngoại lệ từConvert.ToInt32()
— Nolonar

Bạn có thể sử dụng regex ^ \ d + $. Hoặc đánh giá từng ký tự cho IsDigit.
— paparazzo

Câu trả lời:


103

Nếu bạn chỉ cần boolkết quả, chỉ cần sử dụng giá trị trả về và bỏ qua outtham số.

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

Chỉnh sửa : Trong khi đó, bạn cũng có thể xem mã nguồn ban đầu :

System.Int32.TryParse


Nếu tôi muốn biết điều gì đó thực sự được triển khai như thế nào, tôi đang sử dụng ILSpyđể dịch ngược mã .NET.

Đây là kết quả:

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

Và không, tôi không thể nhìn thấy bất kỳ thứ gì Try-Catchstrên đường:

// 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
Nó phức tạp hơn sau đó tôi nên :) Cảm ơn bạn!
— Speti43 Ngày

19

Chỉ vì int.TryParsemang lại cho bạn giá trị không có nghĩa là bạn cần phải giữ nó; bạn có thể khá vui khi làm điều này:

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

Bạn có thể bỏ qua temphoàn toàn nếu không cần thiết. Nếu bạn cần nó, thì hey, nó đang chờ bạn khi bạn muốn.

Đối với nội bộ, theo như tôi nhớ, nó cố gắng đọc các byte thô của chuỗi dưới dạng int và kiểm tra xem kết quả có hợp lệ hay không; nó không đơn giản như việc lặp qua tìm kiếm các ký tự không phải số.


16

Bây giờ chúng ta có thể viết C # 7.0 trở lên trong C # 7.0:

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

Đây không phải là để trả lời câu hỏi.
— themefield 19/09/18

1
ra ngoài làm gì?
— mrid

@mrid Nó chỉ định rằng một biến trong phạm vi gọi đang được cấp cho phạm vi phương thức có quyền ghi. Ví dụ: Nếu một biến int someIntđược chuyển cho int.TryParselike int.TryParse(out someInt), int.TryParsecó thể đặt đầu ra của nó someInt, mặc dù nó thường nằm ngoài phạm vi.
— timelmer

@themefield - nó trả lời câu hỏi này ngay trong phần nội dung của bài đăng: "Vì vậy, các câu hỏi là: 1) Có chức năng nào chỉ có thể cung cấp kết quả bool".
— antiduh

13

TryParse là cách tốt nhất để phân tích cú pháp hoặc xác thực trong một dòng:

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

Mô tả ngắn:

  1. nNumber sẽ khởi tạo bằng 0,
  2. int.TryParse () hãy thử phân tích cú pháp "InputString" và xác thực nó, nếu thành công được đặt thành nNumber.
  3. short if ?: kiểm tra kết quả int.TryParse (), trả về nNumber hoặc 1 làm giá trị mặc định.

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

Devin-burke thân mến, bạn nói đúng, nhưng nó hoạt động. Tôi sử dụng nó nhiều thời gian, mà không cần bất kỳ lỗi hoặc cảnh báo ...
— Zolfaghari

8

Regex được biên dịch để tăng tốc độ, hãy tạo nó một lần và sử dụng lại.
Cái mới mất nhiều thời gian hơn IsMatch.
Điều này chỉ kiểm tra tất cả các chữ số.
Nó không kiểm tra phạm vi.
Nếu bạn cần kiểm tra phạm vi thì TryParse là cách để đi.

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

2

Kiểm tra chương trình đơn giản này để hiểu int.TryParse

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

Đầu ra là: 7788

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.