StringComparer.CurrentCultureIgnoreCase 在 .NET 中多次调用的效率

use*_*840 4 .net c# stringcomparer

我一直在使用StringComparer.CurrentCultureIgnoreCase不区分大小写的比较和散列。但是在检查参考源之后,我发现它每次调用都会创建一个新实例(那么它不应该是一个静态函数吗?只是为了形式)。无论如何,我的问题是,当您需要进行多次比较(例如IEquality<T>实现)时,这样做是否有效:

// 2 instances per call
return StringComparer.CurrentCultureIgnoreCase.Equals(this.a, other.a)
  && StringComparer.CurrentCultureIgnoreCase.Equals(this.b, other.b) .. etc ..
Run Code Online (Sandbox Code Playgroud)

或者可能:

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 ..
}
Run Code Online (Sandbox Code Playgroud)

或者甚至缓存/池比较器,这样它们就不会在每次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 ..
}
Run Code Online (Sandbox Code Playgroud)

对最佳实践有何感受?

(感谢 michael-liu 指出 OrdinalIgnoreCase 不是一个新实例,我已切换到 CurrentCultureIgnoreCase)

Mic*_*Liu 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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

由于在实际的 .NET 可再发行组件中省略了 Contract.Ensures 调用,因此几乎肯定会通过抖动内联剩余的字段访问。

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

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

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

return String.Equals(this.a, other.a, StringComparison.OrdinalIgnoreCase);
Run Code Online (Sandbox Code Playgroud)

现在,即使您使用 CurrentCulture 或 CurrentCultureIgnoreCase,您也完全不必担心 StringComparer 分配,并且代码仍然易于阅读。