อะไรคือความแตกต่างระหว่างอินเตอร์เฟส IComparable และ IEquatable?


98

อินเทอร์เฟซทั้งสองดูเหมือนจะเปรียบเทียบวัตถุเพื่อความเท่าเทียมกันดังนั้นความแตกต่างที่สำคัญระหว่างพวกเขาคืออะไร?

คำตอบ:


189

IEquatable ทดสอบว่าวัตถุสองชิ้นเท่ากันหรือไม่

IComparable กำหนดลำดับรวมของวัตถุที่กำลังเปรียบเทียบ

ตัวอย่างเช่นIEquatableจะบอกคุณว่า 5 ไม่เท่ากับ 7 IComparableจะบอกคุณว่า 5 มาก่อน 7



10

นอกเหนือจากคำตอบของ Greg D:

คุณอาจนำไปใช้IComparableโดยไม่ต้องใช้IEquatableสำหรับคลาสที่การสั่งซื้อบางส่วนเหมาะสมและในกรณีที่คุณต้องการให้ผู้บริโภคสรุปว่าเพียงเพราะCompareTo()ส่งคืนค่าศูนย์สิ่งนี้ไม่ได้หมายความว่าอ็อบเจ็กต์นั้นเท่ากัน (เพื่อวัตถุประสงค์อื่นนอกเหนือจากการเรียงลำดับ)


10
ฟังดูคล้ายกับตัวเปรียบเทียบกรณีพิเศษมากกว่าการใช้งานวัตถุIComparableอย่างถูกต้อง คุณสามารถหาตัวอย่างที่มีความหมายที่CompareTo(…) == 0ไม่ได้หมายความถึงความเท่าเทียมกันได้หรือไม่? ฉันทำไม่ได้อย่างแน่นอน ในความเป็นจริงสัญญาอินเทอร์เฟซ (ตาม MSDN) กำหนดให้CompareTo(…) == 0มีความเท่าเทียมกัน ที่จะนำมันโผงผางในกรณีเช่นคุณใช้พิเศษComparatorวัตถุไม่ได้IComparableดำเนินการ
Konrad Rudolph

2
@Konrad - ฉันได้ระบุข้อแม้หลายประการ - ประเภทนี้ไม่ได้ใช้ IEquatable (เห็นได้ชัดว่าผู้ริเริ่มไม่ต้องการรวมการทดสอบความเท่าเทียมกัน) และผลลัพธ์ CompareTo จะใช้สำหรับการเรียงลำดับไม่ใช่เพื่อประเมินความเท่าเทียมกัน นอกจากนี้คุณยังได้รับคำถามว่าความเท่าเทียมกันใดที่เกี่ยวข้อง (การอ้างอิงค่าโดยไม่สนใจแอตทริบิวต์ "ตามอำเภอใจ" - หนังสือสีน้ำเงินที่มีความยาว 500 หน้าอาจ "เท่ากับ" หนังสือสีแดงที่มีความยาว 500 หน้าสำหรับวัตถุประสงค์ของ IComparable)
Damien_The_Unbeliever

4
ประโยคสุดท้ายของคุณไม่ถูกต้องและนี่คือข้อผิดพลาดที่ฉันต้องการชี้ให้เห็น: IComparableไม่เหมาะสมอย่างยิ่ง สิ่งที่คุณมีคือการสั่งซื้อที่เฉพาะเจาะจงซึ่งใช้เฉพาะในสถานการณ์พิเศษเพียงอย่างเดียว สำหรับสถานการณ์เช่นนี้การใช้งานทั่วไปIComparableเป็นสิ่งที่ผิด นี่คือสิ่งที่IComparerมีไว้สำหรับ ตัวอย่างเช่นไม่สามารถสั่งคนได้อย่างมีความหมาย แต่สามารถสั่งซื้อได้ตามเงินเดือนขนาดรองเท้าจำนวนฝ้ากระหรือน้ำหนัก ดังนั้นเราจะใช้IComparers ที่แตกต่างกันสำหรับกรณีเหล่านี้ทั้งหมด
Konrad Rudolph

2
@Konrad Rudolph: แล้วคลาส "ScheduledEvent" ที่ควรจะทำ "บางอย่าง" ในช่วงเวลาใดเวลาหนึ่ง ความหมายของประเภทจะบ่งบอกถึงการจัดลำดับความหมายตามธรรมชาติที่แข็งแกร่งมากโดยพิจารณาจากเวลาที่การกระทำนั้นควรจะเกิดขึ้น แต่อาจมีเหตุการณ์ที่แตกต่างกันเกิดขึ้นพร้อมกันได้อย่างง่ายดาย อาจต้องใช้ IComparer ที่ระบุด้วยตนเอง แต่ฉันจะหลีกเลี่ยงว่าการมีตัวเปรียบเทียบในตัวคลาสจะสะดวกกว่า
supercat

4
@supercat ความสะดวกเป็นสิ่งสำคัญ แต่ไม่ใช่ทุกอย่าง ความถูกต้อง (เช่นเดียวกับความสอดคล้องทางตรรกะ) มีความสำคัญมากกว่าและระบบชนิดคงที่เป็นเครื่องมือสำคัญในการตรวจสอบความสอดคล้องเชิงตรรกะนี้ ด้วยการละเมิดสัญญาอินเทอร์เฟซที่คุณนำมาใช้แสดงว่าคุณกำลังล้มล้างระบบประเภท นี่ไม่ใช่ความคิดที่ดีและฉันไม่อยากแนะนำเลย ใช้ตัวเปรียบเทียบภายนอกสำหรับสถานการณ์ดังกล่าว
Konrad Rudolph

7

ตามที่ระบุไว้ในMSDN Page สำหรับ IEquatable :

อินเทอร์เฟซ IComparable กำหนดCompareToวิธีการซึ่งกำหนดลำดับการจัดเรียงของอินสแตนซ์ของประเภทการนำไปใช้งาน อินเทอร์เฟซ IEquatable กำหนดEqualsวิธีการซึ่งกำหนดความเท่าเทียมกันของอินสแตนซ์ของประเภทการนำไปใช้งาน

Equals เทียบกับ CompareTo


4

IComparable <T> กำหนดวิธีการเปรียบเทียบเฉพาะประเภทซึ่งสามารถใช้เพื่อสั่งซื้อหรือจัดเรียงวัตถุ

IEquatable <T> กำหนดวิธีการทั่วไปที่สามารถใช้ในการกำหนดความเท่าเทียมกัน


สมมติว่าคุณมีคลาส Person

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person p1 = new Person() { Name = "Person 1", Age = 34 };
Person p2 = new Person() { Name = "Person 2", Age = 31 };
Person p3 = new Person() { Name = "Person 3", Age = 33 };
Person p4 = new Person() { Name = "Person 4", Age = 26 };

List<Person> people = new List<Person> { p1, p2, p3, p4 };

ในการจัดเรียงวัตถุเหล่านี้คุณสามารถpeople.Sort();ใช้ได้

แต่สิ่งนี้จะทำให้เกิดข้อยกเว้น

ป้อนคำอธิบายภาพที่นี่

Framework ไม่รู้ว่าจะเรียงลำดับวัตถุเหล่านี้อย่างไร คุณต้องบอกวิธีจัดเรียงIComparableอินเทอร์เฟซการใช้งาน

public class Person : IComparable
{
    public string Name { get; set; }
    public int Age { get; set; }

    public int CompareTo(object obj)
    {
        Person otherPerson = obj as Person;
        if (otherPerson == null)
        {
            throw new ArgumentNullException();
        }
        else
        {
            return Age.CompareTo(otherPerson.Age);
        }
    }
}

สิ่งนี้จะจัดเรียงอาร์เรย์อย่างถูกต้องด้วยSort()วิธีการ


ถัดไปเพื่อเปรียบเทียบวัตถุสองชิ้นคุณสามารถใช้Equals()วิธีการ

var newPerson = new Person() { Name = "Person 1", Age = 34 };
var newPersonIsPerson1 = newPerson.Equals(p1);

สิ่งนี้จะกลับมาfalseเนื่องจากEqualsmethod ไม่ทราบวิธีเปรียบเทียบวัตถุสองชิ้น ดังนั้นคุณต้องใช้IEquatableอินเทอร์เฟซและบอกกรอบวิธีการเปรียบเทียบ ขยายจากตัวอย่างก่อนหน้านี้จะมีลักษณะเช่นนี้

public class Person : IComparable, IEquatable<Person>
{
    //Some code hidden

    public bool Equals(Person other)
    {
        if (Age == other.Age && Name == other.Name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

1
ขอบคุณสำหรับคำอธิบายที่ดีนี้ คำถาม: ทำไมIEquatableใช้ทั่วไป<Person>และIComparableไม่?
veuncent
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.