在.NET GetHashCode方法中,很多地方都使用.NET 方法.特别是在快速查找集合中的项目或确定相等性时.是否有关于如何GetHashCode为我的自定义类实现覆盖的标准算法/最佳实践,因此我不会降低性能?
默认实现如何GetHashCode()工作?它是否有效且足够好地处理结构,类,数组等?
我试图决定在什么情况下我应该自己打包,在什么情况下我可以安全地依赖默认实现来做好.如果可能的话,我不想重新发明轮子.
我试图理解IEqualityComparer接口的GetHashCode方法的作用.
以下示例来自MSDN:
using System;
using System.Collections.Generic;
class Example {
static void Main() {
try {
BoxEqualityComparer boxEqC = new BoxEqualityComparer();
Dictionary<Box, String> boxes = new Dictionary<Box,
string>(boxEqC);
Box redBox = new Box(4, 3, 4);
Box blueBox = new Box(4, 3, 4);
boxes.Add(redBox, "red");
boxes.Add(blueBox, "blue");
Console.WriteLine(redBox.GetHashCode());
Console.WriteLine(blueBox.GetHashCode());
}
catch (ArgumentException argEx) {
Console.WriteLine(argEx.Message);
}
}
}
public class Box {
public Box(int h, int l, int w) {
this.Height = h;
this.Length = l;
this.Width = w;
}
public int …Run Code Online (Sandbox Code Playgroud) 有没有办法获取实例的唯一标识符?
GetHashCode()对于指向同一实例的两个引用是相同的.但是,两个不同的实例可以(很容易)获得相同的哈希码:
Hashtable hashCodesSeen = new Hashtable();
LinkedList<object> l = new LinkedList<object>();
int n = 0;
while (true)
{
object o = new object();
// Remember objects so that they don't get collected.
// This does not make any difference though :(
l.AddFirst(o);
int hashCode = o.GetHashCode();
n++;
if (hashCodesSeen.ContainsKey(hashCode))
{
// Same hashCode seen twice for DIFFERENT objects (n is as low as 5322).
Console.WriteLine("Hashcode seen twice: " + n + " (" + hashCode + ")");
break; …Run Code Online (Sandbox Code Playgroud) 我之前从未真正这样做过,所以我希望有人可以告诉我正确实现我的类的Except()和GetHashCode()的重写.
我正在尝试修改类,以便我可以使用LINQ Except()方法.
public class RecommendationDTO{public Guid RecommendationId { get; set; }
public Guid ProfileId { get; set; }
public Guid ReferenceId { get; set; }
public int TypeId { get; set; }
public IList<TagDTO> Tags { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
public bool IsActive { get; set; }
public object ReferencedObject { get; set; }
public bool IsSystemRecommendation { get; set; }
public int VisibilityScore { get; …Run Code Online (Sandbox Code Playgroud) 我只是很好奇,因为我猜它会影响性能.它是否考虑完整的字符串?如果是,长字符串会很慢.如果它只考虑字符串的一部分,它将具有不良的性能(例如,如果它只考虑字符串的开头,如果HashSet主要包含具有相同的字符串,则它将具有不良性能.
我已经阅读了关于何时以及如何覆盖的10个不同的问题,GetHashCode但仍然有一些我不太了解的问题.大多数实现GetHashCode都是基于对象字段的哈希码,但是引用的是值的值GetHashCode永远不会在对象的生命周期内发生变化.如果它所基于的字段是可变的,那该怎么办?另外,如果我确实希望字典查找等基于引用相等而不是我的重写Equals?
我主要是Equals为了方便单元测试我的序列化代码,我假设序列化和反序列化(在我的情况下为XML)会导致引用相等,所以我想确保至少它的值是正确的.Equals在这种情况下,这种不良做法是否会被覆盖?基本上在大多数执行代码中,我希望引用相等,而且我总是使用,==而不是重写.我应该创建一个新的方法ValueEquals或什么而不是覆盖Equals?我曾经认为框架总是使用==而不是Equals比较事物,因此我认为覆盖是安全的,Equals因为在我看来,如果你想要有与==运算符不同的第二个等式定义,那么它的目的是什么.从阅读其他几个问题虽然看起来并非如此.
编辑:
看来我的意图不清楚,我的意思是99%的时候我想要普通的老参考平等,默认行为,没有惊喜.对于非常罕见的情况,我希望值相等,并且我希望通过使用.Equals而不是显式请求值相等==.
当我这样做时,编译器建议我也覆盖GetHashCode,这就是这个问题的出现方式.GetHashCode当应用于可变对象时,似乎存在矛盾的目标,即:
a.Equals(b)那时a.GetHashCode()应该== b.GetHashCode().a.GetHashCode()永远不应该改变的价值a.当一个可变对象时,这些看起来自然是矛盾的,因为如果对象的状态发生变化,我们期望值的.Equals()变化,这意味着GetHashCode应该改变以匹配变化.Equals(),但GetHashCode不应该改变.
为什么会出现这种矛盾呢?这些建议不适用于可变对象吗?可能是假设,但可能值得一提的是我指的是不是结构的类.
解析度:
我将JaredPar标记为已被接受,但主要用于评论互动.总结我从中学到的是,在边缘情况下实现所有目标和避免可能的古怪行为的唯一方法是仅覆盖Equals并GetHashCode基于不可变字段或实现IEquatable.这种类似似乎削弱了覆盖Equals引用类型的有用性,因为从我看到的大多数引用类型通常没有不可变字段,除非它们存储在关系数据库中以使用它们的主键来标识它们.
我在这里提出的许多问题涉及IEquatable的实现.我发现正确实现起来非常困难,因为在天真的实现中存在许多隐藏的错误,我发现的关于它的文章非常不完整.我想找到或写出一个必须包括的权威参考:
这样一个完整的参考已经存在?
PS:即使是MSDN引用对我来说也是有缺陷的
根据MSDN,散列函数必须具有以下属性:
如果两个对象比较相等,则每个对象的GetHashCode方法必须返回相同的值.但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值.
只要没有对对象状态的修改来确定对象的Equals方法的返回值,对象的GetHashCode方法必须始终返回相同的哈希代码.请注意,这仅适用于当前应用程序的执行,并且如果再次运行应用程序,则可以返回不同的哈希代码.
为获得最佳性能,哈希函数必须为所有输入生成随机分布.
我一直在以下场景中找到自己:我创建了一个类,实现IEquatable<T>并重写了object.Equals(object).MSDN声明:
重写Equals的类型也必须覆盖GetHashCode; 否则,Hashtable可能无法正常工作.
然后它通常会为我停止一点.因为,你如何正确覆盖object.GetHashCode()?从来没有真正知道从哪里开始,这似乎是很多陷阱.
在StackOverflow中,有很多与GetHashCode重写相关的问题,但大多数问题似乎都是针对非常特殊的情况和具体问题.因此,我想在这里得到一个很好的汇编.概述与一般建议和指南.该做什么,不该做什么,常见的陷阱,从哪里开始,等等.
我希望它特别针对C#,但我认为它对其他.NET语言也有同样的作用(?).
我想也许最好的方法是每个主题创建一个答案,首先是快速简短的答案(如果可能的话,尽可能接近单行),然后可能会有更多信息,并以相关问题,讨论,博客文章等结束. ,如果有的话.然后,我可以创建一个帖子作为接受的答案(将其置于顶部),只需一个"目录".尽量保持简洁明了.而且不要只链接到其他问题和博客文章.尝试采用它们的本质,然后链接到源(特别是因为源可能会消失.另外,请尝试编辑和改进答案,而不是创建许多非常相似的答案.
我不是一个非常优秀的技术作家,但我至少会尝试格式化答案,使它们看起来很相似,创建目录等.我也会尝试在这里搜索一些相关的问题来回答部分问题.这些并且可能拉出我能管理的那些的本质.但由于我在这个主题上不是很稳定,所以我会尽量远离这个主题:p
引用 Eric Lippert的GetHashCode指南和规则:
规则:GetHashCode的消费者不能依赖它随着时间的推移或跨appdomains的稳定性
假设您有一个Customer对象,其中包含一系列字段,如Name,Address等.如果在两个不同的进程中使用完全相同的数据生成两个这样的对象,则它们不必返回相同的哈希代码.如果你在星期二的一个进程中创建这样一个对象,关闭它,并在星期三再次运行程序,哈希码可能会有所不同.
这在过去曾经被人咬伤过.System.String.GetHashCode的文档特别指出,两个相同的字符串在CLR的不同版本中可以具有不同的哈希码,实际上它们也是如此.不要在数据库中存储字符串哈希并期望它们永远是相同的,因为它们不会.
那么创建一个可以存储在数据库中的字符串的HashCode的正确方法是什么?
(请告诉我,我不是第一个在我写的软件中留下这个错误的人!)
gethashcode ×10
.net ×8
c# ×8
hashcode ×4
equals ×2
hash ×2
algorithm ×1
database ×1
equality ×1
iequatable ×1
overriding ×1
string ×1
unique ×1