1. 程式人生 > >C# 中Parse 和TryParse的效率問題

C# 中Parse 和TryParse的效率問題

我們知道在C#中數值型別中轉換有Parse和TryParse兩個方法,兩個最大的區別是,如果字串不滿足轉換要求,Parse方法將會引發一個異常;TryParse方法則不會引發異常,它會返回fasle,同時將傳入的值置為0。
下面我用測試用例來驗證兩者的效率問題:
測試轉換成功的效率問題:
這裡寫圖片描述
同過上面的圖片可以看到 在轉換成功時,效率方面TryParse 略微佔了上風。
測試轉換失敗效率的問題
這裡寫圖片描述
通過這個測試可以發現TryParse的效率明顯高於Parse,當然讀者還可以測試其它型別的轉換。
可是為什麼TryParse的效率比Parse的效率高呢?建議讀者看看原始碼就明白了。
微軟提供的程式碼如下:
Parse 相關程式碼如下:

  [Pure]
        public static int Parse(String s) {
            return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
        }

    [System.Security.SecuritySafeCritical]  // auto-generated
        internal unsafe static Int32 ParseInt32(String s, NumberStyles style, NumberFormatInfo info) {

            Byte * numberBufferBytes = stackalloc
Byte[NumberBuffer.NumberBufferBytes]; NumberBuffer number = new NumberBuffer(numberBufferBytes); Int32 i = 0; StringToNumber(s, style, ref number, info, false); if ((style & NumberStyles.AllowHexSpecifier) != 0) { if (!HexNumberToInt32(ref
number, ref i)) { throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); } } else { if (!NumberToInt32(ref number, ref i)) { throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); } } return i; } [System.Security.SecuritySafeCritical] // auto-generated private unsafe static void StringToNumber(String str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo info, Boolean parseDecimal) { if (str == null) { throw new ArgumentNullException("String"); } Contract.EndContractBlock(); Contract.Assert(info != null, ""); fixed (char* stringPointer = str) { char * p = stringPointer; if (!ParseNumber(ref p, options, ref number, null, info , parseDecimal) || (p - stringPointer < str.Length && !TrailingZeros(str, (int)(p - stringPointer)))) { throw new FormatException(Environment.GetResourceString("Format_InvalidString")); } } } private static Boolean HexNumberToInt32(ref NumberBuffer number, ref Int32 value) { UInt32 passedValue = 0; Boolean returnValue = HexNumberToUInt32(ref number, ref passedValue); value = (Int32)passedValue; return returnValue; } [System.Security.SecuritySafeCritical] // auto-generated private unsafe static Boolean HexNumberToUInt32(ref NumberBuffer number, ref UInt32 value) { Int32 i = number.scale; if (i > UInt32Precision || i < number.precision) { return false; } Char* p = number.digits; Contract.Assert(p != null, ""); UInt32 n = 0; while (--i >= 0) { if (n > ((UInt32)0xFFFFFFFF / 16)) { return false; } n *= 16; if (*p != '\0') { UInt32 newN = n; if (*p != '\0') { if (*p >= '0' && *p <= '9') { newN += (UInt32)(*p - '0'); } else { if (*p >= 'A' && *p <= 'F') { newN += (UInt32)((*p - 'A') + 10); } else { Contract.Assert(*p >= 'a' && *p <= 'f', ""); newN += (UInt32)((*p - 'a') + 10); } } p++; } // Detect an overflow here... if (newN < n) { return false; } n = newN; } } value = n; return true; }

TryParse的相關程式碼

     [Pure]
        public static bool TryParse(String s, out Int32 result) {
            return Number.TryParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
        }

        [System.Security.SecuritySafeCritical]  // auto-generated
        internal unsafe static Boolean TryParseInt32(String s, NumberStyles style, NumberFormatInfo info, out Int32 result) {

            Byte * numberBufferBytes = stackalloc Byte[NumberBuffer.NumberBufferBytes];
            NumberBuffer number = new NumberBuffer(numberBufferBytes);
            result = 0;

            if (!TryStringToNumber(s, style, ref number, info, false)) {
                return false;
            }

            if ((style & NumberStyles.AllowHexSpecifier) != 0) {
                if (!HexNumberToInt32(ref number, ref result)) { 
                    return false;
                }
            }
            else {
                if (!NumberToInt32(ref number, ref result)) {
                    return false;
                }
            }
            return true;           
        }

  internal static Boolean TryStringToNumber(String str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo numfmt, Boolean parseDecimal) {   
            return TryStringToNumber(str, options, ref number, null, numfmt, parseDecimal);
        }


        [System.Security.SecuritySafeCritical]  // auto-generated
        [System.Runtime.CompilerServices.FriendAccessAllowed]
        internal unsafe static Boolean TryStringToNumber(String str, NumberStyles options, ref NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, Boolean parseDecimal) {   

            if (str == null) {
                return false;
            }
            Contract.Assert(numfmt != null, "");

            fixed (char* stringPointer = str) {
                char * p = stringPointer;
                if (!ParseNumber(ref p, options, ref number, sb, numfmt, parseDecimal) 
                    || (p - stringPointer < str.Length && !TrailingZeros(str, (int)(p - stringPointer)))) {
                    return false;
                }
            }

            return true;
        }
 using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EfficietionProject
{
    class Program
    {
        static string val = "123a";
        static void Main(string[] args)
        {
            int counter = 1;
            Console.Write("輸入測試的數量:");
            string line = null;
            while ((line = Console.ReadLine()) != null)
            {
                if (!int.TryParse(line, out counter))
                {
                    counter = 1;
                }
                Stopwatch sw = Stopwatch.StartNew();
                Parse(counter);
                sw.Stop();
                Console.WriteLine("Parse:" + sw.ElapsedMilliseconds.ToString());
                sw.Restart();
                TryParse(counter);
                sw.Stop();
                Console.WriteLine("TryParse:" + sw.ElapsedMilliseconds.ToString());
                Console.Write("輸入測試的數量:");
            }
        }
        static void Parse(int counter)
        {
            int res = 0;
            for (int i = 0; i < counter; i++)
            {
                try
                {
                    res = int.Parse(val);
                }
                catch
                {
                    res = 0;
                }
            }

        }
        static void TryParse(int counter)
        {
            int res = 0;
            for (int i = 0; i < counter; i++)
            {
                int.TryParse(val, out res);
            }
        }
    }
}