首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >String.Equals(字符串1,子字符串(0,x),string2)是否优于string2 1 string2(String2)?

String.Equals(字符串1,子字符串(0,x),string2)是否优于string2 1 string2(String2)?
EN

Stack Overflow用户
提问于 2012-01-15 05:21:06
回答 2查看 3.1K关注 0票数 13

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

MSDN给出了以下字符串比较建议这里,但没有说明为什么要

MSDN示例(沿着上面的页面半途而废):

代码语言:javascript
复制
public static bool IsFileURI(string path) 
{
   path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
   return true;
}

MSDN建议:

但是,前面的示例使用String.StartsWith(String,StringComparison)方法测试相等性。由于比较的目的是测试相等性,而不是排序字符串,所以更好的替代方法是调用Equals方法,如下例所示。

代码语言:javascript
复制
public static bool IsFileURI(string path)
{
   if (path.Length < 5) return false;

   return String.Equals(path.Substring(0, 5), "FILE:", 
                    StringComparison.OrdinalIgnoreCase);
}

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

讨论要点:

  1. 显然,第一个示例中的return true;是一个bug,应该是return path.StartsWith(...);我们可以安全地忽略这一点,因为VB代码是正确的。
  2. 在比较相等之前创建一个子字符串似乎只使用了另一个内存资源,而不仅仅是调用String.StartsWith()。
  3. 长度<5测试是一个不错的短路,但它可以与前面的代码一样使用。
  4. 第二个例子可以解释为更清晰的代码,但我关心的是性能。创建子字符串似乎没有必要。
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-01-15 05:32:13

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

代码语言:javascript
复制
return TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0;

String.Equals调用:

代码语言:javascript
复制
return TextInfo.CompareOrdinalIgnoreCase(this, value) == 0;

CompareOrdinalIgnoreCase调用一个dotPeek没有显示的私有方法,但我的预感是,StartsWith调用的重载遍历整个字符串,而Equals调用的重载在确定等式后立即停止。

如果需要考虑性能,请尝试使用应用程序典型的值来度量两者。

出于好奇,我试着测量这两种情况,而且看起来Equals明显地更快了。当我使用发布版本运行下面的代码时,Equals的速度几乎是StartsWith的两倍

代码语言:javascript
复制
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();
        }
    }
}
票数 4
EN

Stack Overflow用户

发布于 2012-01-15 06:31:37

答案就在您在Ordinal String Operations标题下提供的代码示例下面找到。

.NET框架中的字符串可以包含嵌入的空字符。序号比较和区域性敏感比较(包括使用不变区域性的比较)之间最明显的区别之一是如何处理字符串中嵌入的空字符。当使用String.Compare和String.Equals方法执行区分区域性的比较(包括使用不变区域性的比较)时,这些字符将被忽略。因此,在区分区域性的比较中,包含嵌入空字符的字符串可以被视为等于不包含空字符的字符串。 重要 虽然字符串比较方法忽略了嵌入的空字符,但字符串搜索方法(如String.Contains、String.EndsWith、String.IndexOf、String.LastIndexOf和String.StartsWith )却不这样做。

这意味着使用序数比较的String.StartsWithString.Equals将返回不同的结果。也就是说,使用顺序比较的全部目的是防止土耳其系统上的人绕过安全问题(当忽略情况时,"f" != "F" )。这意味着如果测试使用了"FIL\0E:",那么仍然有人可以通过传递一个类似于String.StartsWith的文件URI来规避安全问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8867710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档