简体   繁体   English

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

[英]StringComparer.CurrentCultureIgnoreCase efficiency with multiple calls in .NET

I've been using StringComparer.CurrentCultureIgnoreCase for case-insensitive comparisons and hashing. 我一直在使用StringComparer.CurrentCultureIgnoreCase进行不区分大小写的比较和散列。 But after checking the Reference Source I see it creates a new instance with every call (shouldn't it be a static function then? Just for form's sake). 但是在检查引用源之后,我看到它会在每次调用时创建一个新实例(那么它不应该是一个静态函数吗?只是为了形式)。 Anyway my question is, when you have multiple comparisons to do, like an IEquality<T> implementation, is it efficient to do: 无论如何,我的问题是,当你进行多次比较时,比如IEquality<T>实现,它是否有效:

// 2 instances per call
return StringComparer.CurrentCultureIgnoreCase.Equals(this.a, other.a)
  && StringComparer.CurrentCultureIgnoreCase.Equals(this.b, other.b) .. etc ..

Or maybe: 或者可能:

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 ..
}

Or even cache/pool the comparers so they arn't created every time Equals() is called? 或者甚至缓存/汇集比较器,以便每次调用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 ..
}

Any feelings on which is best practice? 任何感觉都是最佳实践?

(Thanks to michael-liu for pointing out by original reference to OrdinalIgnoreCase is not a new instance, I've switched to CurrentCultureIgnoreCase which is) (感谢michael-liu通过对OrdinalIgnoreCase的原始引用指出不是一个新实例,我已切换到CurrentCultureIgnoreCase,这是)

According to the reference source , OrdinalIgnoreCase returns the same static instance each time: 根据引用源 ,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;
        }
    }

Since the Contract.Ensures call is omitted in the actual .NET redistributables, the remaining field access will almost certainly be inlined by the jitter. 由于在实际的.NET可再发行组件中省略了Contract.Ensures调用,因此剩余的字段访问几乎肯定会被抖动内联。

(The same applies to InvariantCulture, InvariantCultureIgnoreCase, and Ordinal.) (这同样适用于InvariantCulture,InvariantCultureIgnoreCase和Ordinal。)

On the other hand, CurrentCulture and CurrentCultureIgnoreCase do return new instances each time you access them because the current culture may change between accesses. 另一方面,CurrentCulture和CurrentCultureIgnoreCase每次访问时都会返回新实例,因为当前文化可能会在访问之间发生变化。 Should you cache the comparer in this case? 在这种情况下你应该缓存比较器吗? Personally, I wouldn't make my code more complicated unless profiling indicated there was a problem. 就个人而言,除非分析表明存在问题,否则我不会使我的代码更复杂。

In this particular case, though, I usually compare strings for equality like this: 但是,在这种特殊情况下,我通常比较字符串是否相同:

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

Now you don't have to worry about StringComparer allocations at all, even if you use CurrentCulture or CurrentCultureIgnoreCase, and the code is still straightforward to read. 现在您根本不必担心StringComparer分配,即使您使用CurrentCulture或CurrentCultureIgnoreCase,代码仍然可以直接阅读。

Never underestimate the cost of making code thread-safe. 永远不要低估使代码线程安全的成本。 CurrentCulture is a property of a thread and of course different threads can run with different cultures. CurrentCulture是一个线程的属性,当然不同的线程可以运行不同的文化。 You'd need a cache that can be accessed in a thread-safe way to store the objects. 您需要一个可以线程安全的方式访问的缓存来存储对象。 A cache without a retirement policy is a memory leak, now you also have to keep track of last-usage and a way to retire objects that haven't been used for a while. 没有退出策略的缓存是内存泄漏,现在您还必须跟踪上次使用情况以及退出一段时间未使用的对象的方法。 None is obvious. 没有一个是显而易

Just much simpler and cheaper to create the object when needed. 在需要时创建对象更简单,更便宜。 It is quite small, cheaper than a string. 它很小,比一根绳子便宜。 It is very unlikely to last long. 它不太可能持续很长时间。 Memory allocated from gen #0 that doesn't get promoted is very cheap. 从gen#0分配的内存未被提升是非常便宜的。

The .NET Framework is heavily micro-optimized, they didn't fumble this one. .NET Framework经过了大量的微优化,他们没有摸索这个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM