เมื่อใดควรใช้ IComparable <T> เทียบกับ IComparer <T>


101

ฉันกำลังพยายามคิดว่าจะต้องใช้อินเทอร์เฟซใดต่อไปนี้ ทั้งคู่ทำสิ่งเดียวกันเป็นหลัก ฉันจะใช้อันอื่นเมื่อไหร่


ดูตัวอย่างและคำอธิบายที่ยอดเยี่ยมได้ที่นี่: support.microsoft.com/nl-nl/help/320727/…
ม.ค.

คำตอบ:


96

ดีที่พวกเขาไม่ได้ค่อนข้างเป็นสิ่งเดียวกับIComparer<T>ที่จะดำเนินการกับชนิดที่มีความสามารถของการเปรียบเทียบสองวัตถุที่แตกต่างกันในขณะที่IComparable<T>มีการใช้งานเกี่ยวกับประเภทที่มีความสามารถที่จะเปรียบเทียบตัวเองกับกรณีอื่น ๆ ประเภทเดียวกัน

ฉันมักจะใช้IComparable<T>เป็นบางครั้งเมื่อฉันต้องการทราบว่าอินสแตนซ์อื่นเกี่ยวข้องกับthisอินสแตนซ์อย่างไร IComparer<T>มีประโยชน์สำหรับการจัดเรียงคอลเลกชันเป็นฐานIComparer<T>นอกการเปรียบเทียบ


9
IComparer <T> ยังช่วยให้คุณมีคลาสสำหรับการเรียงลำดับแต่ละประเภทที่คุณต้องการ ตัวอย่าง; PersonLastFirstNameComparer, PersonFirstLastNameComparer หรือ PersonAgeComparer
Eric Schneider

มีวิธีง่ายๆที่คุณใช้ในการจดจำหรือไม่? ฉันมักจะต้องมองขึ้นไปทุกครั้ง
amadib

59
@amadib คิดว่าIComparableเป็นผมเทียบเคียง ซึ่งหมายความว่าฉันสามารถเปรียบเทียบกับอย่างอื่นได้ และอ่านIComparerว่าฉันเป็นตัวเปรียบเทียบฉันแค่เปรียบเทียบซึ่งหมายความว่าฉันเปรียบเทียบบางสิ่ง
nawfal

@newfal คุณควรใส่สิ่งนี้เป็นคำตอบ ฉันคิดว่ามันเป็นคำอธิบายที่ดีที่สุดสำหรับที่นี่
Gene S

42

ใช้IComparable<T>เมื่อคลาสมีการเปรียบเทียบภายใน

ใช้IComparer<T>เมื่อคุณต้องการวิธีการเปรียบเทียบที่นอกเหนือจากการเปรียบเทียบที่แท้จริงของคลาสหากมี


28

ขึ้นอยู่กับนิติบุคคล ตัวอย่างเช่นต่อไปนี้สำหรับชั้นเรียนเช่น "นักเรียน" จะเหมาะสมที่จะมี IComparable ตามชื่อ

class Student : IComparable 
{
    public string Name { get; set; }
    public int MathScore { get; set; }
    public int EnglishScore { get; set; }

    public int TotalScore 
    {
        get
        {
            return this.MathScore + this.EnglishScore; 
        }
    }

    public int CompareTo(object obj)
    {
        return CompareTo(obj as Student);  
    }

    public int CompareTo(Student other)
    {
        if (other == null)
        {
            return 1;
        }
        return this.Name.CompareTo(other.Name);  
    }
}

แต่ถ้าครู "A" ต้องการเปรียบเทียบนักเรียนตาม MathScore และครู "B" ต้องการเปรียบเทียบนักเรียนตาม EnglishScore จะเป็นการดีที่จะใช้ IComparer แยกกัน (เหมือนรูปแบบกลยุทธ์)

class CompareByMathScore : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        if (x.MathScore > y.MathScore)
          return 1;
        if (x.MathScore < y.MathScore)
          return -1;
        else
          return 0;
    }
}

ทำให้วิธีการเปรียบเทียบเป็นแบบคงที่เพื่อให้ใช้งานได้ง่าย
ม.ค.

9

ทุกอย่างขึ้นอยู่กับว่าประเภทของคุณไม่แน่นอนหรือไม่ คุณควรเพียงใช้ IComparable เกี่ยวกับประเภทที่ไม่แน่นอน โปรดทราบว่าหากคุณใช้ IComparable คุณต้องลบล้าง Equals พร้อมด้วยตัวดำเนินการ ==,! =, <และ> (ดูคำเตือนการวิเคราะห์โค้ด CA1036)

อ้างถึง Dave G จากโพสต์บล็อกนี้ :

แต่คำตอบที่ถูกต้องคือการใช้ IComparer แทน IComparable หากวัตถุของคุณไม่แน่นอนและส่งผ่านอินสแตนซ์ของ IComparer ไปยังฟังก์ชันการเรียงลำดับเมื่อจำเป็น

เนื่องจาก IComparer เป็นเพียงวัตถุที่ใช้แล้วทิ้งที่ใช้สำหรับการจัดเรียง ณ เวลานั้นวัตถุของคุณจึงมีความหมายที่ไม่แน่นอนที่คุณต้องการได้ นอกจากนี้ยังไม่ต้องการหรือแนะนำให้ใช้ Equals, GetHashCode หรือ == - คุณมีอิสระที่จะกำหนดมันในแบบที่คุณต้องการ

สุดท้ายคุณสามารถกำหนด IComparer หลายรายการสำหรับประเภทของคุณสำหรับการจัดเรียงในฟิลด์ต่างๆหรือด้วยกฎที่แตกต่างกัน สิ่งนี้มีความยืดหยุ่นมากกว่าการจมอยู่กับคำจำกัดความเดียว

กล่าวโดยย่อ: ใช้ IComparable สำหรับประเภทมูลค่าและ IComparer สำหรับประเภทอ้างอิง


6

คำอธิบายง่ายๆผ่านเรื่องราว

บาสเก็ตบอลมัธยม. เป็นการเลือกสนามของโรงเรียนสำหรับทีม ฉันต้องการได้คนที่สูงที่สุด / ดีที่สุด / เร็วที่สุดในทีมของฉัน ฉันจะทำอย่างไร?

IComparer Interface - เปรียบเทียบคนสองคนแยกคน

  • สิ่งนี้ทำให้ฉันสามารถเปรียบเทียบผู้ชายสองคนที่เรียงกัน ......... โดยพื้นฐานแล้ว Fred vs John .......... ฉันโยนมันลงในคลาสคอนกรีตที่ใช้อินเทอร์เฟซ Compare(Fred, John)และพ่นออกมาว่าใครดีกว่ากัน

แล้ว IComparable ล่ะ? - เปรียบเทียบตัวเองกับคนอื่น

เมื่อเร็ว ๆ นี้คุณอยู่บน FB หรือไม่? คุณเห็นคนอื่น ๆ ทำสิ่งที่ยอดเยี่ยม: เดินทางไปทั่วโลกสร้างสิ่งประดิษฐ์ในขณะที่ฉันกำลังทำบางอย่างที่ไม่ค่อยดีนัก แต่สิ่งที่เราทำคือการใช้อินเทอร์เฟซ IComparable

  • เรากำลังเปรียบเทียบอินสแตนซ์ปัจจุบัน (ตัวคุณเอง) กับวัตถุอื่น (บุคคลอื่น) ซึ่งเป็นประเภทเดียวกัน (บุคคล)

แล้ว Comparer Class ล่ะ?

คลาส Comparer เป็นคลาสพื้นฐานนามธรรมที่ใช้อินเตอร์เฟส IComparer คุณควรได้รับจากคลาสนี้เพื่อนำไปใช้อย่างเป็นรูปธรรม อย่างไรก็ตาม Microsoft ขอแนะนำให้คุณใช้คลาส Comparer แทนที่จะใช้อินเทอร์เฟซ IComparer:

เราขอแนะนำให้คุณได้รับมาจากคลาส Comparer แทนที่จะใช้อินเทอร์เฟซ IComparer เนื่องจากคลาส Comparer มีการใช้อินเทอร์เฟซที่ชัดเจนของเมธอด ICompare เปรียบเทียบและคุณสมบัติดีฟอลต์ที่ได้รับตัวเปรียบเทียบดีฟอลต์สำหรับอ็อบเจ็กต์

สรุป

  • IComparer - จัดเรียงสองสิ่งและเปรียบเทียบ
  • IComparable - เปรียบเทียบตัวเองกับคนอื่น ๆ บน FB

หวังว่าเรื่องราวต่างๆจะช่วยให้คุณจำได้


1
ฉันชอบวิธีการแสดงแนวคิดหลักของคุณ อาจจะดีกว่าถ้าคุณรวมคลาส Comparer (T) ไว้ในการแข่งขันนี้ แม้จะไม่รวมอยู่ในคำถาม :)
Kevman

4

อย่างที่คนอื่นบอกพวกเขาไม่ได้ทำแบบเดียวกัน

ไม่ว่าในกรณีใดทุกวันนี้ฉันมักจะไม่ใช้ IComparer ทำไมฉัน? ความรับผิดชอบ (เอนทิตีภายนอกที่ใช้ในการเปรียบเทียบวัตถุสองชิ้น) สามารถจัดการได้สะอาดกว่าด้วยนิพจน์แลมบ์ดาซึ่งคล้ายกับวิธีการทำงานของ LINQ ส่วนใหญ่ เขียนแลมบ์ดาอย่างรวดเร็วซึ่งจะนำวัตถุมาเปรียบเทียบเป็นอาร์กิวเมนต์และส่งคืนบูล และถ้าออบเจ็กต์กำหนดการดำเนินการเปรียบเทียบภายในของตัวเองก็สามารถใช้ IComparable แทนได้


1
-1: การส่งคืนบูลไม่เทียบเท่ากับ IComparer IComparer ส่งคืนค่าที่สามารถน้อยกว่าศูนย์ / ศูนย์ / มากกว่าศูนย์และโดยทั่วไปจะใช้สำหรับการเรียงลำดับ
โจ

และเมื่อนั่นคือสิ่งที่คุณต้องการคุณจะส่งคืน int (หรือดีกว่ายังคงเป็น enum) แทน เป็นเรื่องใหญ่จริงหรือ?
jalf

2
คุณยังสามารถคืนค่าบูลได้เนื่องจากน้อยกว่าการดำเนินการเดียวที่คุณต้องการเพื่อจัดเรียงลำดับ
jalf

การใช้งาน IComparer จำเป็นต้องกำหนดเพียงครั้งเดียวหากคุณต้องการใช้ตรรกะการเรียงลำดับในสถานที่อื่น ๆ นิพจน์แลมบ์ดาจะต้องถูกเขียนหลายครั้ง
oɔɯǝɹ

oɔɯǝɹ - จากนั้นคุณสามารถจัดเก็บการอ้างอิงถึงผู้รับมอบสิทธิ์ที่เขียนเป็นนิพจน์แลมบ์ดาเพื่อนำมาใช้ซ้ำได้เช่นกัน
jpierson

3

IComparable กล่าวว่าวัตถุสามารถเปรียบเทียบกับวัตถุอื่นได้ IComparer คือวัตถุที่สามารถเปรียบเทียบสิ่งของสองชิ้นได้


2

IComparer เป็นอินเทอร์เฟซที่ใช้ในการจัดเรียง Array อินเทอร์เฟซนี้จะบังคับให้คลาสใช้เมธอด Compare (T x, T y) ซึ่งจะเปรียบเทียบอ็อบเจ็กต์ทั้งสอง อินสแตนซ์ของคลาสที่ใช้อินเทอร์เฟซนี้ถูกใช้ในการเรียงลำดับของ Array

IComparable เป็นอินเทอร์เฟซที่ใช้งานในประเภทที่ต้องการเปรียบเทียบวัตถุทั้งสองชนิดเดียวกันอินเทอร์เฟซที่เปรียบเทียบได้นี้จะบังคับให้คลาสใช้วิธีการต่อไปนี้ CompareTo (T obj)

IEqualityComparer เป็นอินเทอร์เฟซที่ใช้ในการค้นหาวัตถุไม่ว่าจะเป็น Equal หรือไม่ตอนนี้เราจะเห็นสิ่งนี้ในตัวอย่างที่เราต้องหาความแตกต่างของวัตถุในคอลเล็กชัน อินเทอร์เฟซนี้จะใช้วิธีการเท่ากับ (T obj1, T obj2)

ตอนนี้เราใช้ตัวอย่างเรามีคลาสพนักงานจากคลาสนี้เราต้องสร้างคอลเล็กชัน ตอนนี้เรามีข้อกำหนดดังต่อไปนี้

เรียงลำดับ Array โดยใช้ Array class 2 ต้องการคอลเลกชันโดยใช้ Linq: Remove the Duplicate เรียงลำดับตามสูงไปต่ำลบ ID พนักงานหนึ่งคน

abstract public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { set; get; }
}

public enum SortType
{
    ByID,
    BySalary
}

ระดับสาธารณะ EmployeeIdSorter: IComparer {public int Compare (Employee x, Employee y) {if (x.Id <y.Id) return 1; อื่นถ้า (x.Id> y.Id) ส่งกลับ -1; อื่นกลับ 0; }}

    public class EmployeeSalarySorter : IComparer<Employee>
    {
        public int Compare(Employee x, Employee y)
        {
            if (x.Salary < y.Salary)
                return 1;
            else if (x.Salary > y.Salary)
                return -1;
            else
                return 0;
        }
    }

สำหรับข้อมูลเพิ่มเติมอ้างอิงด้านล่าง http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

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