我正在使用字符串比较来测试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建议第二个例子更好?
讨论要点:
显然,return true;
在第一个例子中是一个bug,应该是return path.StartsWith(...);
.我们可以安全地忽略这一点,因为VB代码是正确的.
在比较相等性之前创建子字符串似乎只使用另一个内存资源,而不仅仅是调用String.StartsWith().
长度<5测试是一个很好的短路,但它可以与之前的代码一样使用.
第二个例子可以被解释为更清晰的代码,但我关注的是性能.子串的创建似乎是不必要的.
查看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)