เป็นเวลานานแล้ว แต่อย่างไรก็ตามฉันคิดว่ามันยังคงจำเป็นที่จะต้องให้คำตอบที่ถูกต้องสำหรับคำถามนี้รวมถึงคำอธิบายเกี่ยวกับ whys และ hows คำตอบที่ดีที่สุดคือการอ้างถึง MSDN อย่างละเอียด - อย่าพยายามสร้างกฎของคุณเองพวก MS รู้ว่าพวกเขากำลังทำอะไรอยู่
แต่สิ่งแรกสิ่งแรก: แนวทางที่อ้างถึงในคำถามนั้นผิด
ตอนนี้พวกเขามีสองคน
เหตุผลแรก : หากคำนวณ hashcode ด้วยวิธีการนั้นจะไม่เปลี่ยนแปลงในช่วงอายุการใช้งานของวัตถุแม้ว่าตัววัตถุจะเปลี่ยนแปลงไปกว่าที่มันจะทำลายสัญญาเท่ากับ
เตือนความจำ: "ถ้าวัตถุสองรายการเปรียบเทียบเท่ากันเมธอด GetHashCode สำหรับแต่ละวัตถุจะต้องส่งคืนค่าเดียวกันอย่างไรก็ตามหากวัตถุสองรายการไม่เปรียบเทียบกันเท่ากันเมธอด GetHashCode สำหรับวัตถุทั้งสองนั้นไม่จำเป็นต้องส่งคืนค่าที่ต่างกัน"
ประโยคที่สองมักตีความผิด ๆ ว่า "กฎข้อเดียวคือเมื่อเวลาสร้างวัตถุ hashcode ของวัตถุที่เท่ากันจะต้องเท่ากัน" ไม่รู้จริงๆว่าทำไม แต่นั่นเป็นเรื่องเกี่ยวกับสาระสำคัญของคำตอบส่วนใหญ่ที่นี่เช่นกัน
นึกถึงวัตถุสองชิ้นที่มีชื่อโดยใช้ชื่อในวิธีการเท่ากับ: ชื่อเดียวกัน -> สิ่งเดียวกัน สร้างอินสแตนซ์ A: ชื่อ = โจสร้างอินสแตนซ์ B: ชื่อ = ปีเตอร์
Hashcode A และ Hashcode B ส่วนใหญ่จะไม่เหมือนกัน จะเกิดอะไรขึ้นเมื่อชื่อของอินสแตนซ์ B เปลี่ยนเป็นโจ
ตามแนวทางจากคำถามแฮชโค้ดของ B จะไม่เปลี่ยนแปลง ผลลัพธ์ของสิ่งนี้จะเป็น: A.Equals (B) ==> จริง แต่ในเวลาเดียวกัน: A.GetHashCode () == B.GetHashCode () ==> false
แต่พฤติกรรมนี้ถูกห้ามอย่างชัดเจนโดยเท่ากับ & hashcode-contract
เหตุผลที่สอง : ในขณะที่มันเป็นจริงการเปลี่ยนแปลงในแฮชโค้ดอาจทำให้รายการแฮชและวัตถุอื่น ๆ ที่ใช้แฮชโค้ดกลับกันก็เป็นจริงเช่นกัน การไม่เปลี่ยนแฮชโค้ดจะเป็นกรณีที่แย่ที่สุดที่จะได้รับรายการแฮชที่วัตถุต่าง ๆ จำนวนมากจะมีแฮชโค้ดเดียวกันและจะอยู่ในแฮชถังเดียวกัน - เกิดขึ้นเมื่อวัตถุถูกเริ่มต้นด้วยค่ามาตรฐานตัวอย่างเช่น
ทีนี้มาถึงจุดต่ำสุดแล้วในแวบแรกดูเหมือนว่าจะมีความขัดแย้ง - ทั้งสองทางรหัสจะแตก แต่ไม่มีปัญหามาจากการเปลี่ยนแปลงหรือ hashcode ไม่เปลี่ยนแปลง
สาเหตุของปัญหาได้อธิบายไว้อย่างดีใน MSDN:
จากรายการ hashtable ของ MSDN:
วัตถุหลักจะต้องไม่เปลี่ยนรูปตราบเท่าที่ใช้เป็นกุญแจใน Hashtable
นี่หมายความว่า:
วัตถุใด ๆ ที่สร้าง hashvalue ควรเปลี่ยน hashvalue เมื่อวัตถุนั้นเปลี่ยนแปลง แต่จะต้องไม่ - แน่นอนต้องไม่ - อนุญาตการเปลี่ยนแปลงใด ๆ กับตัวมันเองเมื่อมันถูกใช้ภายใน Hashtable (หรือวัตถุอื่นที่ใช้ Hash แน่นอน) .
ก่อนอื่นวิธีที่ง่ายที่สุดที่แน่นอนคือการออกแบบวัตถุที่ไม่เปลี่ยนรูปสำหรับใช้ในแฮชเทเบิลเท่านั้นซึ่งจะถูกสร้างเป็นสำเนาของวัตถุปกติและวัตถุที่ไม่แน่นอนเมื่อจำเป็น ภายในวัตถุที่ไม่เปลี่ยนรูปมันก็โอเคที่จะแคชรหัส hashcode เนื่องจากมันไม่เปลี่ยนรูป
วิธีที่สองหรือให้วัตถุ "คุณถูกแฮชตอนนี้" - ธงตรวจสอบให้แน่ใจว่าข้อมูลวัตถุทั้งหมดเป็นส่วนตัวตรวจสอบการตั้งค่าสถานะในฟังก์ชั่นทั้งหมดที่สามารถเปลี่ยนข้อมูลวัตถุและโยนข้อมูลข้อยกเว้นหากไม่อนุญาตการเปลี่ยนแปลง ) ตอนนี้เมื่อคุณวางวัตถุในพื้นที่ที่ถูกแฮชตรวจสอบให้แน่ใจว่าตั้งค่าสถานะแล้วและ - รวมถึง - ยกเลิกการตั้งค่าสถานะเมื่อไม่จำเป็นอีกต่อไป เพื่อความสะดวกในการใช้งานฉันแนะนำให้ตั้งค่าสถานะโดยอัตโนมัติภายในวิธี "GetHashCode" - วิธีนี้จะไม่สามารถลืมได้ และการเรียกอย่างชัดเจนของเมธอด "ResetHashFlag" จะทำให้แน่ใจว่าโปรแกรมเมอร์จะต้องคิดว่ามันเป็นหรือไม่ได้รับอนุญาตให้เปลี่ยนข้อมูลวัตถุในขณะนี้
ตกลงสิ่งที่ควรพูดเช่นกัน: มีหลายกรณีที่เป็นไปได้ที่จะมีออบเจ็กต์ที่มีข้อมูลที่ไม่แน่นอนซึ่งแฮชโค้ดยังคงไม่เปลี่ยนแปลงเมื่อมีการเปลี่ยนแปลงข้อมูลวัตถุโดยไม่ละเมิดสัญญา & แฮชโค้ด
อย่างไรก็ตามสิ่งนี้จำเป็นต้องมีวิธีการที่เท่าเทียมกันไม่ได้ขึ้นอยู่กับข้อมูลที่ไม่แน่นอนเช่นกัน ดังนั้นถ้าฉันเขียนวัตถุและสร้างเมธอด GetHashCode ที่คำนวณค่าเพียงครั้งเดียวและเก็บไว้ในวัตถุเพื่อส่งคืนในการโทรในภายหลังฉันต้องอีกครั้ง: ต้องสร้างวิธีการเท่ากับที่จะใช้อย่างแน่นอน ค่าที่เก็บไว้สำหรับการเปรียบเทียบเพื่อให้ A.Equals (B) จะไม่เปลี่ยนจาก false เป็น true เช่นกัน มิฉะนั้นสัญญาจะแตก ผลลัพธ์ของการทำเช่นนี้มักจะเป็นที่วิธีการ Equals นั้นไม่มีเหตุผลใด ๆ - มันไม่ใช่การอ้างอิงแบบเดิม แต่มันก็ไม่ได้มีค่าเท่ากับ บางครั้งสิ่งนี้อาจเป็นพฤติกรรมที่ตั้งใจ (เช่นบันทึกลูกค้า) แต่โดยปกติจะไม่
ดังนั้นเพียงแค่ทำการเปลี่ยนแปลงผล GetHashCode เมื่อข้อมูลวัตถุมีการเปลี่ยนแปลงและหากการใช้วัตถุภายในแฮชโดยใช้รายการหรือวัตถุมีจุดประสงค์ (หรือเป็นไปได้) จากนั้นทำให้วัตถุไม่เปลี่ยนรูปหรือสร้างธงแบบอ่านอย่างเดียวเพื่อใช้สำหรับ อายุการใช้งานของรายการที่ถูกแฮชที่มีวัตถุ
(โดยวิธีการ: ทั้งหมดนี้ไม่เฉพาะ C # oder. NET - เป็นลักษณะของการใช้งาน hashtable ทั้งหมดหรือโดยทั่วไปของรายการดัชนีใด ๆ ที่ระบุข้อมูลของวัตถุไม่ควรเปลี่ยนแปลงในขณะที่วัตถุอยู่ในรายการ พฤติกรรมที่ไม่คาดคิดและคาดเดาไม่ได้จะเกิดขึ้นถ้ากฎนี้ใช้งานไม่ได้ที่ไหนสักแห่งอาจมีการใช้รายการซึ่งจะตรวจสอบองค์ประกอบทั้งหมดในรายการและทำการทำดัชนีรายการใหม่โดยอัตโนมัติ - แต่ประสิทธิภาพของสิ่งเหล่านั้นจะน่ากลัวอย่างที่สุด)