我一直在使用StringComparer.CurrentCultureIgnoreCase进行不区分大小写的比较和散列。但是,在检查了Reference之后,我看到它用每个调用创建了一个新实例(那么,它不是一个静态函数吗?为了形式的缘故)。无论如何,我的问题是,当您需要进行多个比较时,比如一个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()时都创建arn?
// 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最初引用OrdinalIgnoreCase并不是一个新的例子,我转而使用了CurrentCultureIgnoreCase
发布于 2015-06-06 14:55:44
根据参考源,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;
}
}由于在实际的Contract.Ensures再分发表中省略了.NET调用,其余的字段访问几乎肯定会被抖动内联。
(同样适用于InvariantCulture、InvariantCultureIgnoreCase和Ordinal。)
另一方面,CurrentCulture和CurrentCultureIgnoreCase每次访问它们时都会返回新实例,因为当前的区域性可能在访问之间发生变化。在这种情况下,您应该缓存比较器吗?就我个人而言,我不会让我的代码变得更复杂,除非分析表明存在问题。
不过,在这种特殊情况下,我通常比较字符串是否相等,如下所示:
return String.Equals(this.a, other.a, StringComparison.OrdinalIgnoreCase);现在,您根本不必担心StringComparer分配,即使您使用了CurrentCulture或CurrentCultureIgnoreCase,而且代码仍然很容易阅读。
发布于 2015-06-06 17:14:02
千万不要低估代码线程安全的成本。CurrentCulture是线程的一个属性,当然,不同的线程可以在不同的区域性中运行。您需要一个可以以线程安全的方式访问的缓存来存储对象。没有退休策略的缓存是内存泄漏,现在您还必须跟踪最近的使用情况,以及一种将有一段时间没有使用的对象退役的方法。没有一个是显而易见的。
只是在需要时创建对象要简单得多,而且成本更低。它很小,比一根绳子便宜。它不太可能持续很长时间。从第0代分配的内存没有得到提升,非常便宜。
.NET框架是高度微观优化的,他们没有搞错这个框架。
https://stackoverflow.com/questions/30684201
复制相似问题