[C#] GetHashCode() ไม่เท่ากับ Equals() นะ !!!

ช่วงนี้เห็น Rule นึงที่ SonarQube มันแจ้งเตือนมาครับ

"Equals(Object)" and "GetHashCode()" should be overridden in pairs ตัว Message มันหมายความว่าอย่างไรกันนะ หลังจากลองดูคำอธิบายอันนี้จะเป็นในมุมของ Security ครับ เค้าตั้งสมมติฐานว่า ถ้า

  • Object A และ B เมื่อเรียก Equals() แล้ว
  • ถ้าเอา Object A และ B เรียกใช้ GetHashCode() มันควรจะได้ผลลัพธ์ที่เหมือนกันครับ

เอาง่ายๆ ถ้า A และ B เรียก Equals() แล้วได้ true เมื่อไปเรียก GetHashCode() ควรจะได้ค่าเท่ากันครับ ที่ใช้คำว่าควรจะ เพราะจริงๆต้องบอกว่าสอดคล้องกันไปในทางเดียวกันมากกว่า เพราะ

  • Equals() วัดความเหมือน โดยมี Logic บอกว่า ถ้าจะเหมือนต้องดูที่ตรงไหน
  • GetHashCode() บอกความ Unique ของ Object นั้นๆครับ

อันนี้เป็นคำอธิบายในมุมของ Security นะครับ มาดูในของ C# นะครับ ทำไมเมื่อ Override Method GetHashCode() ถึงต้อง Override Method Equals() คู่กันด้วยครับ เหตุผลง่ายๆ คือ อยากให้ Concept เหมือนกันในแง่ Security ครับ เพราะ เจ้า GetHashCode() ใน

  • C# เค้าบอกว่า ถูกเรียกใช้ใน Data Structure ในกลุ่ม hash-based collection เช่น Dictionary ครับ
  • Method Equals() เอง โดยปกติ ไม่ได้แอบไปเรียก GetHashCode() ด้วยครับ

จุดนี้แหละเป็นที่หลายๆคนเข้าใจผิดกันครับ ดังนั้นถ้าจะทำให้ถูกเมื่อมีการแก้ไข Logic ของ Equals() ต้อง Override GetHashCode() ควบคู่กันไปด้วย หรือกลับกัน ถ้าแก้ GetHashCode() ต้อง Override Equals() ตามกันด้วยครับ ถ้าอยากอ่านเรื่อง GetHashCode() เพิ่มเติมสามารถดูใน docs.microsoft ได้เลยครับ

  • เพื่อให้พวก hash-based collection ดึงข้อมูลออกมาได้ถูกครับ และสอดคล้องกับ Equals() ครับ ยกตัวอย่าง เช่น Object 5125 แล้ว ใน Dictionary มันดึงมากันคนละตัวนี้ ได้ 7235 ตรงพิลึกแปลกนะครับ
  • ในแง่ Security ผมเห็นแววโกงแล้วครับ 555 จากตัวอย่างตะกี้ ผมปลอม Object 5125 แล้วทำอะไรที่ไม่ดีกับระบบได้ครับ

ต่อไป ถ้าว่างๆ ผมเขียน Blog เพื่ออธิบาย Code ในส่วนของ C# เพื่อลองทดสอบ เรื่อง GetHashCode() กับ Equals()