4

我一直在使用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 是)

4

2 回答 2

5

根据参考资料,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 可再发行组件中省略了 Contract.Ensures 调用,剩余的字段访问几乎肯定会被抖动内联。

(这同样适用于 InvariantCulture、InvariantCultureIgnoreCase 和 Ordinal。)

另一方面,CurrentCulture 和 CurrentCultureIgnoreCase确实会在您每次访问它们时返回新实例,因为当前文化可能会在访问之间发生变化。在这种情况下你应该缓存比较器吗?就个人而言,除非分析表明存在问题,否则我不会让我的代码更复杂。

不过,在这种特殊情况下,我通常会像这样比较字符串是否相等:

return String.Equals(this.a, other.a, StringComparison.OrdinalIgnoreCase);

现在您根本不必担心 StringComparer 分配,即使您使用 CurrentCulture 或 CurrentCultureIgnoreCase,代码仍然易于阅读。

于 2015-06-06T14:55:44.893 回答
2

永远不要低估使代码线程安全的成本。CurrentCulture 是线程的属性,当然不同的线程可以在不同的文化下运行。您需要一个可以以线程安全方式访问的缓存来存储对象。没有停用策略的缓存是内存泄漏,现在您还必须跟踪上次使用情况以及停用一段时间未使用的对象的方法。没有一个是显而易见的。

在需要时创建对象更简单、更便宜。它很小,比字符串便宜。它不太可能持续很长时间。从 gen #0 分配的未升级的内存非常便宜。

.NET Framework 进行了大量的微优化,他们没有摸索这一点。

于 2015-06-06T17:14:02.110 回答