2016-03-08 102 views
2

我必须将对象与同一类的原始属性进行比较。 意义,我要比较那些:。哪个更快?

struct Identifier 
{ 
    string name; 
    string email; 
} 

与两个字符串的姓名和电子邮件。 我知道我可以为名称和电子邮件创建一个新的标识符实例,并将其传递给equals()。我的应用程序必须非常快速且节省资源。

我知道通过散列码比较不是一个好方法,因为如解释here有碰撞。但碰撞对我来说没问题,我只需要它快。

所以,

1)是通过GetHashCode的(比较检查,如果两个对象的哈希码是相同的)的速度比的equals()?

2)我应该改为创建一个新的比较两个值的标识符实例,做一个新的方法,直接取值?例如

struct Identifier { 
    string name; 
    string email; 

    bool Equals(string name, string email) { 
     // todo comparison via hashcode or equals 
    } 
} 

I would use the Equals() and GetHashCode() method generated by resharper.

+0

GetHashCode不是用于相等比较,而是获取哈希码。 C#中的Hashcode是32位信息,而您的字符串在技术上可能包含无限量的信息。所以非常不同的字符串可能具有相同的哈希码。推荐阅读 - http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden –

+0

请问C#缓存一个字符串的hashCode?因为如果你必须实时计算它,那比比较两个字符串要慢。 – Thilo

+0

@Thilo [不,它不](http://referencesource.microsoft.com/#mscorlib/system/string.cs,0a17bbac4851d0d4)。但是计算两个字符串的哈希代码非常快,您应该在自己的'GetHashCode'实现中使用它们。 –

回答

3

如果将它们保存在Identifier实例上(见下文),比较哈希码可能会更快。然而,与平等比较并不是一回事。

通过比较哈希代码,您可以检查两个项目是否确实是而不是彼此相等:当您获得不同的哈希代码时您会知道这一点。

但是,当哈希码相等时,您不能对等式做出明确声明:项目可能相等或不相等。这就是为什么基于散列的容器必须总是遵循散列码比较,直接或间接比较相等性。

尝试实施这样的比较:

struct Identifier { 
    string name; 
    string email; 
    int nameHash; 
    int emailHash; 
    public Identifier(string name, string email) { 
     this.name = name; 
     nameHash = name.GetHashCode(); 
     this.email = email; 
     emailHash = email.GetHashCode(); 
    } 
    bool Equals(string name, string email) { 
     return name.GetHashCode() == nameHash 
      && email.GetHashCode() == emailHash 
      && name.equals(this.name) 
      && email.equals(this.email); 
    } 
} 

相较于预先计算哈希码将会短路的实际平等比较,这样你就可以节省一些CPU周期时,大部分的比较结束返回false

+1

为什么计算两个哈希码比比较两个字符串更快?两者似乎都必须迭代字符串(并且比较可能会在第一个不匹配字符上短路)。 – Thilo

+1

@Thilo确实不是更快。要查看2个对象是否相等,可以调用Equals方法,这就是全部。 GetHashCode只是用来在散列集合(HashSet,Dictionary ...)中“排序”(有点)你的对象,以便能够以O(1)的复杂度找到它。 – krimog

+0

@Thilo我确信C#高速缓存的字符串哈希代码的Java方式,但快速检查的来源告诉我,我错了:.NET设计师去保存内存。计算哈希代码在CPU高速缓存方面略有优势,因为代码是从顺序位置读取的,因此大多数读取操作都是高速缓存命中。但是,这只适用于很长的字符串,即使这样,影响也很小。无论如何,我改变了答案的措辞,并建议一个明确缓存哈希代码的实现。 – dasblinkenlight

4

经由GetHashCode的比较(检查,如果两个对象 的哈希码是相同的)比的Equals更快()?

你似乎混淆了这两个概念。 GetHashCode的目的不是寻求两个对象实例之间的相等,它只是在那里,因此每个对象都可以轻松地为可能在其上进行中继的任何外部资源提供散列码值。

Equals另一方面,是否有确定平等。应该是两个产生相等的true的方法提供相同的哈希码,但不是相反。

The documentation on object.GetHashCode提供了一个很好的解释:

两个对象是相等的回报相同的散列码。然而, 的情况却并非如此:相同的散列码并不意味着对象 相等,因为不同的(不相等的)对象可以具有相同的散列码 代码。此外,.NET Framework不保证GetHashCode方法的默认 实现,并且此方法 返回的值可能在.NET Framework版本和平台(如 与32位和64位平台)之间有所不同。由于这些原因,请勿将此方法的默认实现用作散列目的的唯一对象标识符 。由此产生两个后果:

  • 您不应该假设相同的散列码暗示对象相等。
  • 您永远不应该在其创建的应用程序域 之外坚持或使用哈希码,因为同一对象可能在应用程序域,进程和平台上散列。

如果你想两个实例之间检查平等,我绝对推荐实施IEquatable<T>和压倒一切的object.GetHashCode

作为一个备注 - 我看到你正在使用struct。你应该注意到struct在C#中的语义不同于C++或C,我希望你知道它们。