鉴于以下课程
public class Foo
{
public int FooId { get; set; }
public string FooName { get; set; }
public override bool Equals(object obj)
{
Foo fooItem = obj as Foo;
if (fooItem == null)
{
return false;
}
return fooItem.FooId == this.FooId;
}
public override int GetHashCode()
{
// Which is preferred?
return base.GetHashCode();
//return this.FooId.GetHashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
我已经覆盖了该Equals方法,因为它Foo代表了Foos表的一行.哪个是覆盖的首选方法GetHashCode?
覆盖为什么重要GetHashCode?
像许多人一样,我使用ReSharper来加速开发过程.当您使用它来覆盖类的相等成员时,它为GetHashCode()生成的代码生成如下所示:
public override int GetHashCode()
{
unchecked
{
int result = (Key != null ? Key.GetHashCode() : 0);
result = (result * 397) ^ (EditableProperty != null ? EditableProperty.GetHashCode() : 0);
result = (result * 397) ^ ObjectId;
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
当然我有一些自己的成员,但我想知道的是为什么397?
我们什么时候应该覆盖' System '命名空间中' Object '类提供的GetHashCode()方法?
我在StackOverflow上阅读了大部分关于的问题GetHashCode.但我仍然不确定是否必须覆盖GetHashCode引用类型.我从另一个问题的某些人那里得到了以下答案:
Object.GetHashCode()使用System.Object类中的内部字段来生成哈希值.创建时,为每个创建的对象分配一个唯一的对象键,存储为整数.这些键从1开始,每次创建任何类型的新对象时都会递增.
如果在.NET Framework 3.5中仍然如此(有人可以确认吗?),那么我在参考类型的默认实现中看到的唯一问题是哈希代码的分布很差.
我会打破我的问题:
a)所以建议覆盖GetHashCode它是否在a中使用Dictionary或者默认实现是否正常?
b)我有很容易做的引用类型,因为它们具有唯一标识它们的字段,但是那些所有成员也是引用类型的引用类型呢.我该怎么办?
在C#中,如果在覆盖Equals()时未能覆盖GetHashCode(),那么具体可能出现什么问题?
我有两个班级之间的关系Credentials<=>UserData.我想MemoryCache用来过滤我的传入请求.
我key = Credential和value = UserData.
(Data)MemoryCache.Default.AddOrGetExisting(GetKey(credential), // must be a string
userData,
DateTime.Now.AddMinutes(5));
Run Code Online (Sandbox Code Playgroud)
如何实现public string GetKey(Credentials credential)传入请求?
Credentials它DataContract包含其他DataContracts类似的GoogleCredentials,FacebookCredentials.它们包含了自己的strings喜欢user_name和password.
现在,缓存项添加了键credential.ToString(),此方法对于Credentials具有相同凭据值的对象返回相同的值,对具有Credentials不同凭据值的实例返回不同的值,这一点很重要.
在Credential类中,我有以下方法
public override int GetHashCode()
{
int hashCode = 0;
if (GoogleCredentials!= null)
{
hashCode ^= GoogleCredentials.GetHashCode();
}
if (FacebookCredentials!= null)
{
hashCode ^= FacebookCredentials.GetHashCode();
}
return hashCode;
}
Run Code Online (Sandbox Code Playgroud) 我正在实施IEquatable<T>,但我很难就可变GetHashCode类的覆盖达成共识。
以下资源都提供了一个实现,GetHashCode如果对象发生更改,则在对象的生命周期内将返回不同的值:
但是,此链接指出GetHashCode不应为可变类型实现,因为如果对象是集合的一部分,则可能会导致不良行为(这也一直是我的理解)。
有趣的是,MSDN 示例实现了GetHashCode仅使用不可变属性,这符合我的理解。但我很困惑为什么其他资源不涵盖这一点。他们真的错了吗?
如果一个类型根本没有不可变属性,编译器会GetHashCode在我重写时警告该类型丢失Equals(object)。在这种情况下,我应该实现它并只调用base.GetHashCode()或禁用编译器警告,还是我错过了某些内容并且GetHashCode应该始终被覆盖和实现?事实上,如果建议不GetHashCode应该为可变类型实现,为什么还要为不可变类型实现呢?与默认实现相比,它只是为了减少冲突GetHashCode,还是实际上添加了更多有形的功能?
总结我的问题,我的困境是,GetHashCode在可变对象上使用意味着如果对象的属性发生变化,它可以在对象的生命周期内返回不同的值。但不使用它意味着比较可能等效的对象的好处会丢失,因为它将始终返回唯一值,因此集合将始终回退到使用Equals其操作。
输入此问题后,“类似问题”框中弹出了另一个问题,似乎涉及同一主题。答案似乎非常明确,因为在GetHashCode实现中只应使用不可变属性。如果没有,那就干脆不写。Dictionary<TKey, TValue>尽管不是 O(1) 性能,但仍然可以正常运行。
好的,所以如果我重写Equals,我需要覆盖GetHashCode,反之亦然.
但我只是想知道:我是否应该总是在任何课程中覆盖这两个?特别是如果我知道我会在字典或类似的集合中使用它们?虽然这是相当直接的,但它仍然是每个班级的额外工作.
System.Object实现是否足以让人担心?
编辑:你能详细说明什么是价值和参考平等?因此,如果我有两个字符串(s1和s2)都是"test",它们的值相等,但由于它们是两个不同的字符串,它们不是引用相等的?好吧,对于字符串来说,这是一个明智的选择,但是你想要参考或价值平等的常见情况是什么?
c# ×6
.net ×4
gethashcode ×2
dictionary ×1
hash ×1
hashcode ×1
iequatable ×1
immutability ×1
mutable ×1
overriding ×1
resharper ×1