上記の回答と私自身の経験に基づいて、いくつかの具体的なシナリオを見てみたいと思います。
経験則では、ハッシュコードが異なる2つのインスタンスは常に等しくないはずですが、ハッシュコードが同じである場合、等しい場合と等しくない場合があります。GetHashCode()
インスタンスをすばやく区別Equals()
するために使用され、同等性を検証するために使用されます(それがあなたにとって意味するものは何でも)。
また、多くの組み込みメカニズムはの実装を探すので、実際にチェックをIEquatable<T>
行うオーバーライドを宣言することをお勧めします。Equals(MyClass)
一意のIDを持つクラス
一意のIDを持つクラスについて考えてみます。次に、equals操作はIDをチェックするだけです。IDのみに依存するハッシュについても同じです。
public class IdClass : IEquatable<IdClass>
{
public int ID { get; } // Assume unique
public string Name { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(IdClass)</code></returns>
public override bool Equals(object obj)
{
if (obj is IdClass other)
{
return Equals(other);
}
return false;
}
/// <summary>
/// Checks for equality among <see cref="IdClass"/> classes
/// </summary>
/// <param name="other">The other <see cref="IdClass"/> to compare it to</param>
/// <returns>True if equal</returns>
public virtual bool Equals(IdClass other)
{
if (other == null) return false;
return ID.Equals(other.ID);
}
/// <summary>
/// Calculates the hash code for the <see cref="IdClass"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode() => ID.GetHashCode();
#endregion
}
プロパティを持つクラス
この場合は上記と似ていますが、比較は2つ以上のプロパティに依存するため、ハッシュコードで非対称に組み合わせる必要があります。これは次のシナリオでより明らかになりますが、一方のプロパティにハッシュがA
あり、もう一方のプロパティにハッシュがある場合、最初のプロパティにハッシュがあり、もう一方のB
プロパティがハッシュである場合とは結果が異なるはずです。B
A
public class RefClass : IEquatable<RefClass>
{
public string Name { get; }
public int Age { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(RefClass)</code></returns>
public override bool Equals(object obj)
{
if (obj is RefClass other)
{
return Equals(other);
}
return false;
}
/// <summary>
/// Checks for equality among <see cref="RefClass"/> classes
/// </summary>
/// <param name="other">The other <see cref="RefClass"/> to compare it to</param>
/// <returns>True if equal</returns>
public virtual bool Equals(RefClass other)
{
if (other == null) { return false; }
return Name.Equals(other.Name)
&& Age.Equals(other.Age);
}
/// <summary>
/// Calculates the hash code for the <see cref="RefClass"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
unchecked
{
int hc = -1817952719;
hc = (-1521134295) * hc + Name.GetHashCode();
hc = (-1521134295) * hc + Age.GetHashCode();
return hc;
}
}
#endregion
}
値ベースのクラス(構造)
struct
これは、値型(宣言)であるためにequalsを再定義し、呼び出す必要==
が!=
あることを除いて、上記の場合とほとんど同じです。
public struct ValClass : IEquatable<ValClass>
{
public int X { get; }
public int Y { get; }
#region IEquatable Members
/// <summary>
/// Equality overrides from <see cref="System.Object"/>
/// </summary>
/// <param name="obj">The object to compare this with</param>
/// <returns>False if object is a different type, otherwise it calls <code>Equals(ValClass)</code></returns>
public override bool Equals(object obj)
{
if (obj is ValClass other)
{
return Equals(other);
}
return false;
}
public static bool operator ==(ValClass target, ValClass other) { return target.Equals(other); }
public static bool operator !=(ValClass target, ValClass other) { return !(target == other); }
/// <summary>
/// Checks for equality among <see cref="ValClass"/> classes
/// </summary>
/// <param name="other">The other <see cref="ValClass"/> to compare it to</param>
/// <returns>True if equal</returns>
public bool Equals(ValClass other)
{
return X == other.X && Y == other.Y;
}
/// <summary>
/// Calculates the hash code for the <see cref="ValClass"/>
/// </summary>
/// <returns>The int hash value</returns>
public override int GetHashCode()
{
unchecked
{
int hc = -1817952719;
hc = (-1521134295) * hc + X.GetHashCode();
hc = (-1521134295) * hc + Y.GetHashCode();
return hc;
}
}
#endregion
}
struct
不変である必要があることに注意してくださいreadonly
。宣言にキーワードを追加することをお勧めします
public readonly struct ValClass : IEquatable<ValClass>
{
}