เมธอด Object.GetHashCode() ใน C# ใช้คืนค่า hash code (รหัสแฮช) ของอ็อบเจ็กต์ — ใช้เป็นค่าเริ่มต้นสำหรับ hash-based collections เช่น Dictionary, HashSet, Hashtable
ไวยากรณ์ (Syntax)
public virtual int GetHashCode();
ตัวอย่างที่ 1: GetHashCode ของ Object และ String
using System;
public class Demo
{
public static void Main()
{
object obj = new object();
string str = "Jim";
Type type1 = obj.GetType();
Type type2 = str.GetType();
Console.WriteLine("Hash Code = " + type1.GetHashCode());
Console.WriteLine("Hash Code = " + type2.GetHashCode());
}
}
ผลลัพธ์
Hash Code = 30015890 Hash Code = 21083178
ตัวอย่างที่ 2: Override GetHashCode ใน Struct (Value Type)
using System;
public struct Value
{
private int v1;
private int v2;
private int v3;
public Value(int v1, int v2, int v3)
{
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}
public override int GetHashCode()
{
return Tuple.Create(v1, v2, v3).GetHashCode();
}
}
public class Demo
{
public static void Main()
{
Value v = new Value(1, 7, 12);
Console.WriteLine(v.GetHashCode()); // 1258
v = new Value(12, 8, 7);
Console.WriteLine(v.GetHashCode()); // 12803
v = new Value(8, 7, 12);
Console.WriteLine(v.GetHashCode()); // 8931
}
}
ผลลัพธ์
1258 12803 8931
สรุปและแนวทางปฏิบัติ (Best Practices)
- Hash code ใช้สำหรับ hash-based collections — Dictionary, HashSet, Hashtable ใช้เพื่อจัดเก็บ/ค้นหา O(1)
- กฎสำคัญ: หาก
a.Equals(b) == trueแล้วa.GetHashCode() == b.GetHashCode()ต้องเป็น true ด้วย (แต่กลับกันไม่จำเป็น) - Override ได้เฉพาะเมื่อ Override Equals() ด้วย — ต้อง override คู่กันเสมอ
- สำหรับ reference types — default implementation ใช้ object identity (reference)
- สำหรับ value types (struct) — default ใช้ reflection/field values — ช้า ควร override เอง
- Hash code ไม่ต้อง unique — ชน (collision) ได้ แต่อย่างน้อยควรกระจายดี
- Hash code ไม่ควรเปลี่ยนแปลง** ระหว่างชีวิตของอ็อบเจ็กต์ (ถ้าใช้เป็น key ใน Dictionary)
รูปแบบการ Override GetHashCode ที่ดี
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public override bool Equals(object obj)
{
return obj is Person other &&
FirstName == other.FirstName &&
LastName == other.LastName &&
Age == other.Age;
}
public override int GetHashCode()
{
// Pattern มาตรฐาน: prime * hash + fieldHash
unchecked // ป้องกัน overflow checking
{
int hash = 17;
hash = hash * 23 + (FirstName?.GetHashCode() ?? 0);
hash = hash * 23 + (LastName?.GetHashCode() ?? 0);
hash = hash * 23 + Age.GetHashCode();
return hash;
}
}
}
// หรือใช้ Tuple (สะดวก แต่ช้ากว่าเล็กน้อย)
public override int GetHashCode() => Tuple.Create(FirstName, LastName, Age).GetHashCode();
// .NET Core 2.1+ / NET 5+ - ใช้ HashCode.Combine (เร็วและสะดวก)
public override int GetHashCode() => HashCode.Combine(FirstName, LastName, Age);
ข้อควรระวัง
- อย่าใช้ GetHashCode() สำหรับ: persistent storage, distributed systems, security/cryptography — ไม่รับประกันความสม่ำเสมอระหว่าง process/run/version
- String.GetHashCode() อาจต่างกันระหว่าง 32-bit/64-bit process และ .NET versions
- สำหรับ cryptographic hash ใช้
System.Security.Cryptography(SHA256, MD5, etc.)