我正在实施IEquatable<T>,但我很难就可变GetHashCode类的覆盖达成共识。
以下资源都提供了一个实现,GetHashCode如果对象发生更改,则在对象的生命周期内将返回不同的值:
但是,此链接指出GetHashCode不应为可变类型实现,因为如果对象是集合的一部分,则可能会导致不良行为(这也一直是我的理解)。
有趣的是,MSDN 示例实现了GetHashCode仅使用不可变属性,这符合我的理解。但我很困惑为什么其他资源不涵盖这一点。他们真的错了吗?
如果一个类型根本没有不可变属性,编译器会GetHashCode在我重写时警告该类型丢失Equals(object)。在这种情况下,我应该实现它并只调用base.GetHashCode()或禁用编译器警告,还是我错过了某些内容并且GetHashCode应该始终被覆盖和实现?事实上,如果建议不GetHashCode应该为可变类型实现,为什么还要为不可变类型实现呢?与默认实现相比,它只是为了减少冲突GetHashCode,还是实际上添加了更多有形的功能?
总结我的问题,我的困境是,GetHashCode在可变对象上使用意味着如果对象的属性发生变化,它可以在对象的生命周期内返回不同的值。但不使用它意味着比较可能等效的对象的好处会丢失,因为它将始终返回唯一值,因此集合将始终回退到使用Equals其操作。
输入此问题后,“类似问题”框中弹出了另一个问题,似乎涉及同一主题。答案似乎非常明确,因为在GetHashCode实现中只应使用不可变属性。如果没有,那就干脆不写。Dictionary<TKey, TValue>尽管不是 O(1) 性能,但仍然可以正常运行。
基本上,到目前为止我有以下内容:
class Foo {
public override bool Equals(object obj)
{
Foo d = obj as Foo ;
if (d == null)
return false;
return this.Equals(d);
}
#region IEquatable<Foo> Members
public bool Equals(Foo other)
{
if (this.Guid != String.Empty && this.Guid == other.Guid)
return true;
else if (this.Guid != String.Empty || other.Guid != String.Empty)
return false;
if (this.Title == other.Title &&
this.PublishDate == other.PublishDate &&
this.Description == other.Description)
return true;
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
所以,问题是:我有一个非必需字段Guid,这是一个唯一标识符.如果没有设置,那么我需要尝试根据不太准确的度量确定相等性,以尝试确定两个对象是否相等.这很好用,但它会弄得GetHashCode()一团糟......我应该怎么做呢?一个天真的实现将是这样的:
public override …Run Code Online (Sandbox Code Playgroud) 这个问题遵循Jon Skeet在这个问题上给出的答案:" 覆盖System.Object.GetHashCode的最佳算法是什么? ".要计算哈希码,请使用以下算法:
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + field1.GetHashCode();
hash = hash * 23 + field2.GetHashCode();
hash = hash * 23 + field3.GetHashCode();
return hash;
}
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么选择数字17和23.我们为什么不选3和5?这也是素数.有人可以解释一下最好的素数是什么以及为什么?
.NET Standard 2.1 / .NET Core 3引入 System.HashCode了快速将字段和值组合为哈希码的功能,而无需关心底层实现。
但是,它仅提供Combine最多 8 个值的方法重载。如果我有一个包含 9 个值(3x3 矩阵)甚至 16 个值(4x4 矩阵)的类,我该怎么办?
我应该简单地将两个Combine调用相加,并在每个调用中传递尽可能多的值吗?
public override int GetHashCode()
=> HashCode.Combine(M11, M12, M13, M21, M22, M23, M31, M32) + HashCode.Combine(M33);
Run Code Online (Sandbox Code Playgroud)
看看来源,我不能完全争论这是否可能有我不知道的影响。
我有这样一堂课:
public class Cycle
{
public List<int> Edges
{
get;
private set;
}
public override bool Equals(object obj)
{
Cycle cycle = (Cycle)obj;
var list1 = cycle.Edges;
var list2 = Edges;
var same = list1.Except(list2).Count() == 0 &&
list2.Except(list1).Count() == 0;
return same;
}
public override int GetHashCode()
{
// return Edges.GetHashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,如果两个Edge列表相同,那么我认为Cycles它们是相同的.
现在的问题是如何实施GetHashCode()?
我尝试过Edges.GetHashCode(),但问题是,两个List<Cycle>具有相同Cycle对象但订单不同的将被视为不同,即使它们应该是相同的.
插入带有hibernate的对象时出现以下异常.从数据库中读取就像一个魅力.我使用MySQL 5.5作为数据库提供程序和hibernate 3.6.5.
我有以下数据库架构:
cell(id,cellid,lac,mcc,mnc,insertTime)
location(id,latitude,longitude,altitude,accuracy,heading,hdop,vdop,pdop,insertTime)
cellatlocation(servingCell,neighbourCell,location,signalStrength,insertTime)
Run Code Online (Sandbox Code Playgroud)
其中单元格和位置中的id是主键和servingCell,neighbourCell和location是cellatlocation中的复合主键.
java.lang.NullPointerException
at org.hibernate.type.descriptor.java.AbstractTypeDescriptor.extractHashCode(AbstractTypeDescriptor.java:88)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:196)
at org.hibernate.type.AbstractStandardBasicType.getHashCode(AbstractStandardBasicType.java:191)
at org.hibernate.type.EntityType.getHashCode(EntityType.java:325)
at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:222)
at org.hibernate.engine.EntityKey.generateHashCode(EntityKey.java:126)
at org.hibernate.engine.EntityKey.<init>(EntityKey.java:70)
at org.hibernate.engine.StatefulPersistenceContext.getDatabaseSnapshot(StatefulPersistenceContext.java:286)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:211)
at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:531)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:103)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:685)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:673)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:345)
at $Proxy17.saveOrUpdate(Unknown Source)
Run Code Online (Sandbox Code Playgroud)
我要插入的类:Cell.java
@Entity
@Table(name = "cell", catalog = "crisis")
public class Cell implements Serializable {
private static final long serialVersionUID = -8532796958180260393L;
@Id
@GeneratedValue(strategy …Run Code Online (Sandbox Code Playgroud) 令我惊讶的是,下面的方法在debug和release中产生了不同的结果:
int result = "test".GetHashCode();
Run Code Online (Sandbox Code Playgroud)
有什么方法可以避免这种情况吗?
我需要一种可靠的方法来散列字符串,我需要在调试和发布模式下保持一致的值.如果可能的话,我想避免编写自己的哈希函数.
为什么会这样?
仅供参考,反射器给了我:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), SecuritySafeCritical]
public override unsafe int GetHashCode()
{
fixed (char* str = ((char*) this))
{
char* chPtr = str;
int num = 0x15051505;
int num2 = num;
int* numPtr = (int*) chPtr;
for (int i = this.Length; i > 0; i -= 4)
{
num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
if (i <= 2)
{
break;
}
num2 = (((num2 << 5) + …Run Code Online (Sandbox Code Playgroud) 我有一个带有字符串属性的类,我需要重写GetHashCode()方法。
class A
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
第一个想法是做这样的事情:
public override int GetHashCode()
{
return Prop1.GetHashCode() ^ Prop2.GetHashCode() ^ Prop3.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)
第二个想法是:
public override int GetHashCode()
{
return String.Join(";", new[] {Prop1, Prop2, Prop3}).GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)
什么是最好的方法?
System.Drawing.PointGetHashCode如果你打算用它来描述图像/位图中的"像素",它有一个非常非常糟糕的方法:它只是X和Y坐标之间的XOR.
因此,对于具有2000x2000大小的图像,它具有荒谬的分数,因为只有对角线中的数字才具有相当好的散列.
GetHashCode正如一些人已经在这里提到的那样,使用未经检查的乘法创建一个合适的方法非常容易.
但是我可以做些什么来使用这种改进的GetHashCode方法HashSet呢?我知道我可以创建自己的类/结构MyPoint并使用这种改进的方法实现它,但是我会破坏我的项目中使用的所有其他代码片段System.Drawing.Point.
是否可以System.Drawing.Point使用某种扩展方法等"覆盖"该方法?或者"告诉" HashSet使用另一个功能而不是GetHashCode?
目前我正在使用SortedSet<System.Drawing.Point>带有自定义IComparer<Point>来存储我的积分.当我想知道该集是否包含Point I调用时BinarySearch.它比HashSet<System.Drawing.Point>.Contains具有10000个聚合的集合中的方法更快,但它没有像HashSet好的哈希一样快.
对于Delphi项目(使用RAD Studio XE7构建),我想创建一个画笔字典.每个字典项包含一个TMyBrush对象作为键,描述要检索的画笔,以及GDI +画笔作为值.
TMyBrush类包含3个字段
在我的字典中,我想根据他的特征检索画笔,而不是他的实例.例如,我希望通过创建本地TMyBrush实例,将其配置为黑色实体,并使用TryGetValue()函数获取匹配的GDI +值,从我的字典中获取黑色实心画笔.为此,我创建了一个TMyBrushComparer.
编写Equals()函数对我来说不是问题.但是我不知道编写GetHashCode()函数的最佳做法是什么.我倾向于写一个这样的函数:
function TMyBrushComparer.GetHashCode(const pValue: TMyBrush): Integer;
begin
Result := BobJenkinsHash(pValue, SizeOf(TMyBrush), 0);
end;
Run Code Online (Sandbox Code Playgroud)
但是我觉得这不是一个很好的做法,这是正确的吗?那么,为我的TMyBrushComparer编写一个好的GetHashCode()函数的最佳实践是什么?
问候
gethashcode ×10
c# ×8
hash ×2
iequatable ×2
.net ×1
debugging ×1
delphi ×1
equals ×1
gdi+ ×1
hashcode ×1
hibernate ×1
immutability ×1
mutable ×1
mysql ×1
performance ×1
primes ×1
release ×1
string ×1
tdictionary ×1