String.Equals(string1.Substring(0,x),string2)是否优于string1.StartsWith(string2)?

Kev*_*ice 13 .net c#

我正在使用字符串比较来测试URL路径StringComparison.OrdinalIgnoreCase.

MSDN提供了以下字符串比较建议这里,但没有说明为什么:

MSDN示例(在上一页的中间):

public static bool IsFileURI(string path) 
{
   path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
   return true;
}
Run Code Online (Sandbox Code Playgroud)

MSDN建议:

"但是,前面的示例使用String.StartsWith(String,StringComparison)方法来测试是否相等.因为比较的目的是测试相等而不是排序字符串,更好的选择是调用Equals方法,如如下例所示."

public static bool IsFileURI(string path)
{
   if (path.Length < 5) return false;

   return String.Equals(path.Substring(0, 5), "FILE:", 
                    StringComparison.OrdinalIgnoreCase);
}
Run Code Online (Sandbox Code Playgroud)

问题:为什么MSDN建议第二个例子更好?

讨论要点:

  1. 显然,return true;在第一个例子中是一个bug,应该是return path.StartsWith(...);.我们可以安全地忽略这一点,因为VB代码是正确的.

  2. 在比较相等性之前创建子字符串似乎只使用另一个内存资源,而不仅仅是调用String.StartsWith().

  3. 长度<5测试是一个很好的短路,但它可以与之前的代码一样使用.

  4. 第二个例子可以被解释为更清晰的代码,但我关注的是性能.子串的创建似乎是不必要的.

Jef*_*ata 4

查看StartsWith使用 dotPeek 的方法,它最终调用一个内部比较函数来比较整个字符串,并根据该比较的返回值返回一个布尔结果:

return TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0;
Run Code Online (Sandbox Code Playgroud)

String.Equals呼叫:

return TextInfo.CompareOrdinalIgnoreCase(this, value) == 0;
Run Code Online (Sandbox Code Playgroud)

CompareOrdinalIgnoreCase调用私有方法,dotPeek 没有显示该方法,但我的预感是 by 调用的重载会StartsWith遍历整个字符串,而Equals一旦确定相等性, by 调用的重载就会停止。

如果性能是一个问题,请尝试使用您的应用程序的典型值来测量这两个值。


出于好奇,我尝试测量两者,看起来确实明显Equals更快。当我使用发布版本运行下面的代码时,Equals速度几乎是以下代码的两倍StartsWith

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var url = "http://stackoverflow.com/questions/8867710/is-string-equalsstring1-substring0-x-string2-better-than-string1-startswit";
            var count = 10000000;
            var http = false;

            Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < count; i++)
            {
                http = url.StartsWith("http:", StringComparison.OrdinalIgnoreCase);
            }

            sw.Stop();

            Console.WriteLine("StartsWith: {0} ms", sw.ElapsedMilliseconds);

            sw.Restart();

            for (int i = 0; i < count; i++)
            {
                http = string.Equals(url.Substring(0, 5), "http:", StringComparison.OrdinalIgnoreCase);
            }

            sw.Stop();

            Console.WriteLine("Equals: {0} ms", sw.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @adrift:Equals 更快的原因很可能是因为您要比较的字符串都是 ASCII(在“String.Equals”中具有优化的情况,但在“StartsWith”中没有)。如果您在前 5 个字符中使用单个非 ASCII 字符,您应该会看到速度优势消失。 (2认同)