ความเท่ากันและการแฮช (ค่ากับการอ้างอิง)
ทำความเข้าใจความเท่ากันของการอ้างอิงกับความเท่ากันของค่า เขียนทับ Equals/GetHashCode อย่างถูกต้อง ใช้ IEquatable และใช้ตัวเปรียบเทียบแบบกำหนดเองกับเซตและพจนานุกรม
ความเท่ากันและการแฮช (ค่ากับการอ้างอิง) เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน
พื้นฐานความเท่าเทียม
เป้าหมาย: ทำให้ความเท่าเทียมทำงานได้ตามที่คาดหวัง
- ความเท่าเทียมตามการอ้างอิงเทียบกับความเท่าเทียมตามค่า
- ข้อตกลงระหว่าง Equals กับ GetHashCode
- IEquatable<T> เพื่อเพิ่มความเร็ว
- ตัวเปรียบเทียบแบบกำหนดเองเมื่อไม่สามารถแก้ไขชนิดข้อมูลได้
จุดที่มักพลาดของความเท่าเทียมตามการอ้างอิง
คลาสมีความเท่าเทียมตามการอ้างอิงเป็นค่าเริ่มต้น ออบเจ็กต์สองรายการที่แยกจากกันแต่มีข้อมูลเดียวกันจะไม่เท่ากัน เว้นแต่คุณจะใช้งานความเท่าเทียมตามค่า
using System;
using System.Collections.Generic;
public sealed class Point // no overrides
{
public int X;
public int Y;
public Point(int x, int y){ X = x; Y = y; }
}
public class Program
{
public static void Main(string[] args)
{
Point a = new Point(1, 2);
Point b = new Point(1, 2);
Console.WriteLine("a == b ? " + (a == b)); // reference equality: False
Console.WriteLine("a.Equals(b) ? " + a.Equals(b)); // False
HashSet<Point> set = new HashSet<Point>();
set.Add(a);
Console.WriteLine("Contains b? " + set.Contains(b)); // False (unexpected)
}
}
ใช้งานความเท่าเทียมตามค่าแล้ว
ใช้งาน IEquatable<T> แล้วเขียนทับ Equals และ GetHashCode ค่าแฮชต้องสอดคล้องกับความเท่าเทียม กล่าวคือ ออบเจ็กต์ที่เท่ากันต้องมีค่าแฮชเดียวกัน
using System;
using System.Collections.Generic;
public sealed class ValuePoint : IEquatable<ValuePoint>
{
public int X;
public int Y;
public ValuePoint(int x, int y){ X = x; Y = y; }
public bool Equals(ValuePoint other)
{
if (ReferenceEquals(other, null)) return false;
if (ReferenceEquals(this, other)) return true;
return X == other.X && Y == other.Y;
}
public override bool Equals(object obj)
{
return Equals(obj as ValuePoint);
}
public override int GetHashCode()
{
// Simple, stable combination (avoid randomness)
unchecked
{
int hash = 17;
hash = hash * 31 + X.GetHashCode();
hash = hash * 31 + Y.GetHashCode();
return hash;
}
}
}
public class Program
{
public static void Main(string[] args)
{
ValuePoint a = new ValuePoint(1, 2);
ValuePoint b = new ValuePoint(1, 2);
Console.WriteLine("a.Equals(b)? " + a.Equals(b)); // True
HashSet<ValuePoint> set = new HashSet<ValuePoint>();
set.Add(a);
Console.WriteLine("Contains b? " + set.Contains(b)); // True (value semantics)
}
}
ตัวเปรียบเทียบแบบกำหนดเอง
ส่ง IEqualityComparer<T> แบบกำหนดเองให้กับ HashSet/Dictionary เมื่อไม่สามารถเปลี่ยนชนิดข้อมูลนั้นเองได้
using System;
using System.Collections.Generic;
public sealed class Person // imagine from a library; cannot edit
{
public string Name;
public int BirthYear;
public Person(string name, int year){ Name = name; BirthYear = year; }
}
public sealed class PersonComparer : IEqualityComparer<Person>
{
public bool Equals(Person a, Person b)
{
if (ReferenceEquals(a, b)) return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return false;
return a.Name == b.Name && a.BirthYear == b.BirthYear;
}
public int GetHashCode(Person p)
{
if (ReferenceEquals(p, null)) return 0;
unchecked
{
int h = 23;
h = h * 31 + (p.Name == null ? 0 : p.Name.GetHashCode());
h = h * 31 + p.BirthYear.GetHashCode();
return h;
}
}
}
public class Program
{
public static void Main(string[] args)
{
Person p1 = new Person("Ada", 1815);
Person p2 = new Person("Ada", 1815);
HashSet<Person> set = new HashSet<Person>(new PersonComparer());
set.Add(p1);
Console.WriteLine("Contains p2? " + set.Contains(p2)); // True via comparer
}
}
ข้อตกลงและจุดที่มักพลาด
กฎ:
- ถ้า Equals(a,b) เป็นจริง ⇒ GetHashCode(a) == GetHashCode(b)
- ความเท่าเทียมควรมีคุณสมบัติเป็น สะท้อนตนเอง สมมาตร และถ่ายทอด
- ควรใช้ฟิลด์ที่ไม่เปลี่ยนแปลงในการคำนวณแฮชเมื่อทำได้
- อย่าใช้ค่าแบบสุ่มใน GetHashCode
ข้อสังเกตเกี่ยวกับโครงสร้างกับคลาส
โครงสร้างจะเปรียบเทียบตามฟิลด์เป็นค่าเริ่มต้น ซึ่งเป็นความหมายเชิงค่า ส่วนคลาสจะเปรียบเทียบตามการอ้างอิง เว้นแต่คุณจะใช้งานความเท่าเทียมตามค่า
using System;
public struct PointS // struct: value type
{
public int X;
public int Y;
public PointS(int x, int y){ X = x; Y = y; }
}
public class Program
{
public static void Main(string[] args)
{
PointS a = new PointS(1, 2);
PointS b = new PointS(1, 2);
Console.WriteLine("Struct equality: " + a.Equals(b)); // True by default (field-wise)
}
}
ข้อตกลงความเท่าเทียมสำหรับคอลเลกชัน
สรุป
สรุป: คลาสต้องมี Equals/GetHashCode และมักต้องมี IEquatable<T> เพื่อให้มีความหมายเชิงค่า หากไม่สามารถแก้ไขชนิดข้อมูลได้ ให้ใช้ตัวเปรียบเทียบแบบกำหนดเอง
คำถามที่พบบ่อย
บทเรียน “ความเท่ากันและการแฮช (ค่ากับการอ้างอิง)” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ความเท่ากันและการแฮช (ค่ากับการอ้างอิง)” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 3 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ความเท่ากันและการแฮช (ค่ากับการอ้างอิง)”
ทำความเข้าใจความเท่ากันของการอ้างอิงกับความเท่ากันของค่า เขียนทับ Equals/GetHashCode อย่างถูกต้อง ใช้ IEquatable และใช้ตัวเปรียบเทียบแบบกำหนดเองกับเซตและพจนานุกรม คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 3 บทเรียน
บทเรียน “ความเท่ากันและการแฮช (ค่ากับการอ้างอิง)” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม
ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- HashSet , SortedSet , Queue , Stack
- ConcurrentDictionary และคอลเลกชันไม่เปลี่ยนแปลง
- ความเท่ากันและการแฮช (ค่ากับการอ้างอิง)