【问题标题】:Which is fast comparison: Convert.ToInt32(stringValue)==intValue or stringValue==intValue.ToString()这是快速比较: Convert.ToInt32(stringValue)==intValue 或 stringValue==intValue.ToString()
【发布时间】:2025-12-28 11:15:06
【问题描述】:

在开发我的应用程序时,我遇到了一些比较的东西:

    string str = "12345";
    int j = 12345;
    if (str == j.ToString())
    {
        //do my logic
    }

我在想上面的东西也可以用:

    string str = "12345";
    int j = 12345;
    if (Convert.ToInt32(str) == j)
    {
        //do my logic
    }

所以我开发了一个示例代码来测试哪个更好

        var iterationCount = 1000000;
        var watch = new Stopwatch();
        watch.Start();
        string str = "12345";
        int j = 12345;
        for (var i = 0; i < iterationCount; i++)
        {
            if (str == j.ToString())
            {
                //do my logic
            }
        }
        watch.Stop();

第二个:

  var iterationCount = 1000000;
    var watch = new Stopwatch();
    watch.Start();
    string str = "12345";
    int j = 12345;
    for (var i = 0; i < iterationCount; i++)
    {
        if (Convert.ToInt32(str) == j)
        {
            //do my logic
        }
    }
    watch.Stop();

在运行上述两个测试时,我发现上述测试所用的时间几乎相同。我想讨论哪个是更好的方法?有没有比两个以上两个更好的方法?

【问题讨论】:

    标签: c# comparison


    【解决方案1】:

    您的测试存在根本缺陷。编译器和运行时真的很聪明,会在编译时和运行时优化代码(JIT-ing)。在这种情况下,您每次都在做同样的事情,这将被编译器发现并优化出来,因此每种方法的时间将是相似的。

    试试这个版本(我只有 .Net 2.0,因此略有改动):

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Diagnostics;
    
    namespace ToStringTest
    {
        class Program
        {
            const int
                iterationCount = 1000000;
    
            static TimeSpan Test1()
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                string str = "12345";
                int j = 12345;
                for (int i = 0; i < iterationCount; i++)
                {
                    if (str == i.ToString())
                    {
                        //do my logic
                    }
                }
                watch.Stop();
                return watch.Elapsed;
            }
    
            static TimeSpan Test2()
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();
                string str = "12345";
                int j = 12345;
                for (int i = 0; i < iterationCount; i++)
                {
                    if (Convert.ToInt32(i) == j)
                    {
                        //do my logic
                    }
                }
                watch.Stop();
                return watch.Elapsed;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine("ToString = " + Test1().TotalMilliseconds);
                Console.WriteLine("Convert = " + Test2().TotalMilliseconds);
            }
        }
    }
    

    你会看到巨大的不同。一个比另一个快两个数量级。确实很明显是哪一个。

    您需要知道各种操作在做什么,才能知道哪个操作从根本上更快。

    将字符串转换为 int 需要以下内容:

    total = 0
    for each character in string
      total = total * 10 + value of charater
    

    ToString 要求:

    string = ""
    while value != 0
      string.AddToFront value % 10
      value /= 10
    

    对于 CPU 来说,乘法比除法更容易、更快。如果选择具有大量乘法的算法与具有大量除法的算法,请始终选择前者,因为它总是更快。

    然后是比较,一个 int - int 比较很简单,将每个值加载到一个寄存器中并比较 - 几个机器指令,你就完成了。两个字符串之间的比较需要一次测试一个字符串中的每个字符 - 在您给出的示例中,它是 5 个字节(一个 int 可能是 4 个字节),这是更多的内存访问。

    【讨论】:

      【解决方案2】:

      嗯 - 性能不应该是唯一重要的事情。

      您应该询问您是要比较实际值还是只比较数字的表示。

      举个例子: “00001”是否等于 1?如果您希望它结合使用 Int.TryParse 将字符串转换为 int,然后进行比较。

      也可能存在其他差异,具体取决于本地设置。也许用户设置了像“1,000,000”这样的数字格式 - 如果你将该字符串与 1000000.ToString() 进行比较,结果将是错误的。

      【讨论】:

        【解决方案3】:

        我更喜欢i.ToString() == str,因为没有任何东西可以保证Convert.ToInt32(str) 不会失败。

        【讨论】:

        • 如果 "000123" != 123,这肯定更好。
        【解决方案4】:

        是的,您将域逻辑显示为在分析循环中,因此您没有测试代码的 ConvertToString 版本之间的时间差;您正在测试转换的组合时间加上业务逻辑的执行。如果您的业务逻辑很慢并且主导转换时间,那么您当然会在每个版本中看到相同的时间。

        现在,除此之外,即使在您知道这是性能瓶颈之前担心这一点也是过早的优化。特别是,如果执行您的域逻辑支配了转换时间,那么两者之间的差异就无关紧要了。所以,选择一个最易读的。

        现在,至于使用哪个版本:您需要首先明确指定您要测试的内容。你的输入是什么? “007”会成为输入吗? “007”与整数 7 不同吗? “1,024”会成为输入吗?是否存在本地化问题?

        【讨论】:

        • 我没有在我的个人资料中使用域逻辑进行测试,它只是写在里面的评论,正如我所展示的那样。
        • 你显示//do my logic。当你在做你的逻辑时,每个人都会解释它,但不想给我们它的细节,而不是你注释掉了逻辑。为了清楚起见,您最好将测试编写为 bool b = Convert.ToInt32(str) == j; 等。
        • @Raghav Khunger:此外,即使您在没有执行域逻辑的情况下测试了这两种方法的性能,我的观点仍然成立:在您知道这是性能瓶颈之前不要担心。相反,请充分说明您正在尝试实现的内容,并编写完成这项工作的最易读、可维护的代码。
        【解决方案5】:

        语义有点不同。 "01" == 1.ToString()false1 == Convert.ToInt32("01")true

        如果解析可能出错(字符串不是有效数字),则Int32.TryParse 比使用Convert.ToInt32() 更快。

        【讨论】:

          【解决方案6】:

          如果性能几乎相同,请使用更易读的版本。

          就我个人而言,我发现 .ToString() 方法更容易理解,并且不像其他方法那样容易出现可能的转换问题。

          【讨论】:

            【解决方案7】:

            如果与 int 进行比较的字符串不能转换为 int,那么第一个将 int 转换为字符串的方法不会引发错误。

            如果您在批量中进行大量测试,转换为字符串将消除由于转换错误而可能引发异常的问题。引发异常需要时间并且会减慢第二次测试。

            【讨论】:

              【解决方案8】:

              好的,我再往前一步,这样测试:

                  int j = 123;
                  for (var i = 0; i < iterationCount; i++)
                  {
                      j.ToString();
                  }
              

              第二个: 字符串 str = "123";

                      for (var i = 0; i < iterationCount; i++)
                      {
                          Convert.ToInt32(str);
                      }
              

              在这种情况下,我发现每次第二个的表现都好一点。在我的情况下,这个数字只会像 100000 而不是 100,000 的形式。我在这篇文章中所做的测试中你的 cmets ??

              【讨论】: