C# 中Parse 和TryParse的效率问题

来源:互联网 发布:js身份证号码格式验证 编辑:程序博客网 时间:2024/05/18 23:56

我们知道在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;        }

完整的源代码如下:
https://referencesource.microsoft.com/#mscorlib/system/int32.cs,225942ed7b7a3252
在打开的网页中直接搜索Parse和TryParse ,便看到对应的源码了。
相关测试的代码如下:

 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);            }        }    }}
1 0