String.Contains方法在内部看起来像这样
public bool Contains(string value)
{
return this.IndexOf(value, StringComparison.Ordinal) >= 0;
}
被调用的IndexOf
重载看起来像这样
public int IndexOf(string value, StringComparison comparisonType)
{
return this.IndexOf(value, 0, this.Length, comparisonType);
}
这里再次调用最终重载,然后调用相关CompareInfo.IndexOf
方法,并带有签名
public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType)
因此,调用最终重载将是最快的(尽管在大多数情况下可能被视为微优化)。
我可能遗漏了一些明显的东西,但是Contains
考虑到中间调用中没有完成其他工作并且在两个阶段都提供相同的信息,为什么该方法不直接调用最终重载?
唯一的好处是,如果最终重载的签名发生变化,只需要进行一次更改(中间方法的更改),还是设计比这更多?
从评论中编辑(有关速度差异说明,请参阅更新 2)
为了澄清我得到的性能差异,以防我在某处犯了错误:我运行了这个基准测试(循环 5 次以避免抖动偏差)并使用这个扩展方法与该方法进行String.Contains
比较
public static bool QuickContains(this string input, string value)
{
return input.IndexOf(value, 0, input.Length, StringComparison.OrdinalIgnoreCase) >= 0;
}
循环看起来像这样
for (int i = 0; i < 1000000; i++)
{
bool containsStringRegEx = testString.QuickContains("STRING");
}
sw.Stop();
Console.WriteLine("QuickContains: " + sw.ElapsedMilliseconds);
在基准测试中,QuickContains
似乎比String.Contains
我的机器快 50%。
更新 2(解释了性能差异)
我在基准测试中发现了一些不公平的东西,这可以解释很多。基准测试本身是测量不区分大小写的字符串,但由于String.Contains
只能执行区分大小写的搜索,ToUpper
因此包含了该方法。这会扭曲结果,不是在最终输出方面,而是至少在简单地衡量String.Contains
非区分大小写搜索中的性能方面。
所以现在,如果我使用这个扩展方法
public static bool QuickContains(this string input, string value)
{
return input.IndexOf(value, 0, input.Length, StringComparison.Ordinal) >= 0;
}
StringComparison.Ordinal
在 2 重载IndexOf
调用和 remove 中使用ToUpper
,该QuickContains
方法实际上变得最慢。IndexOf
并且Contains
在性能方面几乎不相上下。很明显,这是电话歪曲了为什么和ToUpper
之间存在如此差异的结果。Contains
IndexOf
不知道为什么QuickContains
扩展方法变得最慢。Contains
(可能与具有[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
属性的事实有关?)。
关于为什么不直接调用 4 重载方法的问题仍然存在,但该决定似乎并未影响性能(正如 Adrian 和 delnan 在评论中指出的那样)。