อินเทอร์เฟซ IComparable ล้าสมัย /“ เป็นอันตราย” หรือไม่


11

IComparable ใช้งานได้ทางเดียวเท่านั้น

สมมติว่าคุณมีEmployeeชั้นเรียน ในมุมมองหนึ่งคุณต้องการแสดงทั้งหมดEmployeesเรียงตามชื่อ - ในอีกมุมมองตามที่อยู่ คุณจะประสบความสำเร็จได้อย่างไร ไม่อยู่กับIComparableอย่างน้อยก็ไม่มีทางที่เป็นไปได้

IComparable มีเหตุผลในสถานที่ที่ไม่ถูกต้อง

.Sort()อินเตอร์เฟซที่ถูกนำมาใช้โดยการเรียก ในมุมมองที่แสดงCustomerเรียงตามชื่อไม่มีรหัสเลยที่จะบอกว่ามันจะถูกเรียงลำดับอย่างไร
ในทางกลับกันCustomerคลาสจะสมมติว่ามันจะถูกใช้อย่างไรในกรณีนี้มันจะถูกใช้ในรายการเรียงตามชื่อ

IComparable มีการใช้งานโดยปริยาย

ในการเปรียบเทียบกับทางเลือกมันเป็นเรื่องยากมากที่จะเห็นว่ามีการใช้ตรรกะการเปรียบเทียบหรือไม่ สมมติว่า IDE มาตรฐานของคุณและเริ่มจากCustomerชั้นเรียนฉันจะต้อง

  1. ค้นหาการอ้างอิงทั้งหมดถึง Customer
  2. ค้นหาการอ้างอิงเหล่านั้นที่ใช้ในรายการ
  3. ตรวจสอบว่ารายการเหล่านั้นเคย.Sort()เรียกพวกเขา

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

ปัญหาเหล่านี้รวมกันรวมถึงข้อกำหนดที่เปลี่ยนแปลง

เหตุผลที่ฉันมาคิดเรื่องนี้ก็เพราะมันผิดสำหรับฉัน ฉันมีความสุขที่ใช้IComparableในใบสมัครของฉันเป็นเวลา 2 ปีแล้ว ตอนนี้ความต้องการเปลี่ยนแปลงและสิ่งที่ต้องเรียงลำดับใน 2 วิธีที่แตกต่างกัน สังเกตว่าไม่มีความสนุกที่ทำตามขั้นตอนที่อธิบายไว้ในส่วนก่อนหน้า

คำถาม

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


2
ความต้องการ "การจัดเรียงสองวิธีที่แตกต่าง" ใหม่ของคุณคือปลาเฮอริ่งแดง เพื่อแก้ปัญหาสิ่งที่คุณต้องทำคือส่งตัวเปรียบเทียบที่แตกต่างกันไปยังฟังก์ชันการเรียงลำดับของคุณ
Robert Harvey

@RobertHarvey แล้วคุณจะไม่ใช้IComparableอีกต่อไปซึ่งเป็นการตอกย้ำประเด็นของฉัน
R. Schmitz

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

2
ไม่สำคัญว่าจะมีสองอินเตอร์เฟสที่ต่างกัน IComparableถือเป็นกลไกการเปรียบเทียบ เริ่มต้น IComparerจะใช้เมื่อคุณต้องการแทนที่กลไกการเปรียบเทียบเริ่มต้น
Robert Harvey

ตัวอย่างReverseComparer<T>: gist.github.com/jackfarrington/078e7af7bc82482aa634
Berin Loritsch

คำตอบ:


14

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

อย่างไรก็ตามสำหรับโครงสร้างข้อมูลแบบง่าย ๆ มากมายการเรียงลำดับวิธีหนึ่งอาจจะเพียงพอหรือเป็นธรรมชาติ สำหรับกรณีเหล่านี้การมีสถานที่ที่ยอมรับได้หนึ่งแห่งเพื่อใช้ความสัมพันธ์ของคำสั่งซื้อยังคงเป็นวิธีที่ดีในการเก็บรหัส DRY ไว้แทนที่จะใช้ตรรกะเดิมซ้ำในทุกการโทรไปOrderByยังสถานที่ทุกแห่ง

คุณได้ "ใช้ IComparable อย่างมีความสุขในแอปพลิเคชันของคุณเป็นเวลา 2 ปีแล้ว" ตามที่คุณเขียนดังนั้นฉันจึงเห็นว่ามันใช้งานคุณได้ดีเป็นเวลานาน เมื่อตอนนี้คุณต้องตรวจสอบการเปลี่ยนแปลงและทดสอบสายทั้งหมดไปมันก็อาจจะเป็นสัญญาณที่คุณกำลังทำชนิดเดียวกันของการเรียงลำดับตรรกะในหลายสถานที่ซึ่งไม่ได้เป็นความผิดของSort IComparableดังนั้นนี่อาจเป็นโอกาสที่จะรวมตรรกะนี้เข้าด้วยกันในที่เดียวทำให้รหัสของคุณแห้งมากขึ้น


ข้อดีของโครงสร้างข้อมูลแบบง่าย อย่างไรก็ตามย่อหน้าสุดท้ายไม่สมเหตุสมผล 100% สำหรับฉัน หากฉันไม่ได้ใช้IComparableรหัสการเรียงลำดับที่มีอยู่ล่วงหน้าทั้งหมดจะถูกทิ้งไว้โดยไม่มีการแตะต้องในมุมมองที่เกี่ยวข้องขณะที่ฉันจะเพิ่มรหัสการเรียงลำดับใหม่สำหรับมุมมองใหม่เท่านั้น
R. Schmitz

@ R.Schmitz การเรียงลำดับมาก่อนจะทำงานได้อย่างถูกต้องหากไม่มีการIComparableใช้งานที่คุณเขียนหรือไม่
Robert Harvey

3
@ R.Schmitz: แน่นอน แต่ตอนนี้คุณมุ่งมั่นที่จะให้ผู้เปรียบเทียบเสมอ (เว้นแต่คุณจะใช้ OrderBy แน่นอน) ด้วยIComparableคุณจะได้รับการใช้งานเริ่มต้นได้ฟรีและบางครั้งคุณไม่จำเป็นต้องเขียนการใช้งานนั้น
Robert Harvey

2
@ R.Schmitz: ความคิดเห็นล่าสุดของคุณมีจุดสรุปได้ดี ฉันจะไปอีกหน่อย BigIntegerสมมติว่าคุณมีประเภทตัวเลขเช่น ถ้ามันไม่ได้ใช้ตัวดำเนินการเปรียบเทียบ / อินเตอร์เฟสคุณจะนำ IComparer ไปใช้ด้วยตัวเองได้อย่างไร? คุณต้องการเข้าถึงโครงสร้างข้อมูลภายในเพื่อทำสิ่งนั้นได้อย่างมีประสิทธิภาพหรือเลย สมมติว่าคุณมีลูกค้าประเภทหนึ่ง คุณสมบัติที่สาธารณะที่คุณต้องการที่จะเรียงลำดับในการทำมี comparers สำหรับฉันนั่นคือความแตกต่าง: ใช้IComparable<T>ถ้ามันจะไม่มีเหตุผลที่คาดว่าผู้โทรจะใช้เครื่องมือเปรียบเทียบ
Eric Lippert

1
If I hadn't used IComparable, all the pre-existing sorting code would have been left untouched in their respective views, while I'd only add new sorting code for the new view.เพียงเพราะIComparableเป็นที่ดีกว่าการแก้ปัญหาในเวลานั้นไม่ได้หมายความว่ามันเป็นสิ่งที่ดีที่สุดของการแก้ปัญหาในวันนี้ ความคิดเห็นแรกของคุณที่นี่หมายความว่า "เป็น IComparable หรือไม่มีอะไร" ซึ่งไม่เป็นความจริงปัญหาสามารถแก้ไขได้หลายวิธี แอปพลิเคชันสามารถเติบโตในขนาด / ขนาดและสิ่งที่เคยดูเหมาะสมอาจไม่สามารถตอบสนองความต้องการที่เพิ่มขึ้นของแอปพลิเคชันได้
Flater

1

ฉันเห็นด้วยกับความรู้สึกของคุณเกี่ยวกับ IComparable

เพียงแค่ดูข้อสังเกตใน Array.Sort()

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

เราอาจจะไม่ได้เป็นแรงบันดาลใจในขณะนี้อย่างไรก็ตาม! พิจารณาobject.Equals()วิธีการในทุกวัตถุที่ให้คุณเปรียบเทียบวัตถุกับแต่ละอื่น ๆ เพื่อดูว่ามันเป็น "เดียวกัน" หรือไม่

คุณมีสิ่งนั้นอยู่แล้ว แต่ได้รับมอบหมายให้เพิ่มArray.Sort()คุณอาจต้องการเพิ่มobject.Compare(object)

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