CurrentCultureIgnoreCase

CurrentCultureIgnoreCase

我一直在使用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通过原始引用指出ordinalligoreCase不是新实例,我已切换到currentcultureignorecase,即)

最佳答案

根据reference source,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。)
另一方面,current culture和currentcultureignorecase在每次访问时都会返回新实例,因为当前区域性可能在访问之间发生更改。在这种情况下你应该缓存比较器吗?就我个人而言,除非分析表明存在问题,否则我不会使代码更复杂。
不过,在这种情况下,我通常会比较字符串是否相等,如下所示:
return String.Equals(this.a, other.a, StringComparison.OrdinalIgnoreCase);

现在,即使使用currentculture或currentcultureignorecase,也不必担心stringcomparer分配,而且代码仍然很容易阅读。

10-05 18:49