StringComparer.CurrentCultureIgnoreCase在.net中多次调用的效率
本文关键字:调用 效率 CurrentCultureIgnoreCase net StringComparer | 更新日期: 2023-09-27 17:54:13
我一直使用StringComparer.CurrentCultureIgnoreCase
进行不区分大小写的比较和散列。但是在检查参考源后,我看到它创建了一个新的实例与每次调用(它不应该是一个静态函数吗?只是为了形式的缘故)。不管怎样,我的问题是,当你有多个比较要做时,像IEquality<T>
实现,这样做是否有效:
// 2 instances per call
return StringComparer.CurrentCultureIgnoreCase.Equals(this.a, other.a)
&& StringComparer.CurrentCultureIgnoreCase.Equals(this.b, other.b) .. etc ..
或者:
public bool Equals(MyObj other)
{
// 1 instance per call
var equ = StringComparer.CurrentCultureIgnoreCase;
return equ.Equals(this.a, other.a)
&& equ.Equals(this.b, other.b) .. etc ..
}
或者甚至缓存/池比较器,所以他们不创建每次Equals()
被调用?
// 1 instance per thread
[ThreadStatic]
private static StringComparer equ;
public bool Equals(MyObj other)
{
if (equ == null) equ = StringComparer.CurrentCultureIgnoreCase;
return equ.Equals(this.a, other.a)
&& equ.Equals(this.b, other.b) .. etc ..
}
你觉得哪个是最佳实践吗?
(感谢michael-liu指出OrdinalIgnoreCase不是一个新实例,我已经切换到CurrentCultureIgnoreCase,这是)
根据引用源,OrdinalIgnoreCase每次都返回相同的静态实例:
public abstract class StringComparer : ...
{
...
private static readonly StringComparer _ordinalIgnoreCase = new OrdinalComparer(true);
...
public static StringComparer OrdinalIgnoreCase {
get {
Contract.Ensures(Contract.Result<StringComparer>() != null);
return _ordinalIgnoreCase;
}
}
自合同生效。确保调用在实际的。net可重发行版中被省略,剩余的字段访问几乎肯定会被jitter内联。
(同样适用于InvariantCulture, InvariantCultureIgnoreCase和Ordinal.)
另一方面,CurrentCulture和CurrentCultureIgnoreCase 确实在每次访问它们时返回新的实例,因为当前的文化可能在访问之间发生变化。在这种情况下应该缓存比较器吗?就我个人而言,我不会让我的代码变得更复杂,除非分析表明存在问题。
在这个特殊的情况下,我通常会像这样比较字符串是否相等:
return String.Equals(this.a, other.a, StringComparison.OrdinalIgnoreCase);
现在,即使使用CurrentCulture或CurrentCultureIgnoreCase,您也完全不必担心StringComparer的分配,并且代码仍然很容易阅读。
永远不要低估使代码线程安全的代价。CurrentCulture是线程的一个属性,当然不同的线程可以使用不同的区域性运行。您需要一个可以以线程安全的方式访问的缓存来存储对象。没有退役策略的缓存是内存泄漏,现在您还必须跟踪最后使用情况,并找到一种方法来退役一段时间未使用的对象。
在需要时创建对象要简单得多,也便宜得多。它很小,比绳子便宜。它不太可能持续太久。从gen #0分配的内存不被提升是非常便宜的。
. net Framework 进行了大量的微优化,他们没有搞砸这个