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

完整的源代码如下:
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);
            }
        }
    }
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值