ความแตกต่างระหว่างอินเตอร์เฟสทั่วไปของคอลเลกชันทั่วไปใน C #


11

ฉันได้เล่นกับ C # สำหรับ Windows และ ASP.net MVC พัฒนามาระยะหนึ่งแล้ว แต่ฉันยังไม่ชัดเจนในบางพื้นที่ ฉันกำลังพยายามที่จะเข้าใจความแตกต่างขั้นพื้นฐานระหว่างและปัญหาการปฏิบัติงานเกี่ยวกับการใช้และการสับเปลี่ยนชนิดที่คล้ายกันของทั่วไปการเก็บการเชื่อมต่อ

คือความแตกต่างระหว่างสิ่งที่พื้นฐานIEnumerable<T>, ICollection<T>, List<T>(Class)?

ฉันดูเหมือนจะใช้และแลกเปลี่ยนโดยไม่เห็นปัญหาใด ๆ ในแอปพลิเคชันของฉัน นอกจากนี้ยังมีคอลเลกชันทั่วไปที่คล้ายกันมากกว่านี้ที่สามารถแลกเปลี่ยนกับสามเหล่านี้ได้หรือไม่


2
นอกจากนี้ยังมี IList <T> เช่นกัน
jk

คำตอบ:


19

List <T>เป็นคลาสและใช้ทั้งICollection <T>และIEnumerable <T>อินเตอร์เฟส นอกจากนี้ ICollection <T> ยังขยายส่วนต่อประสาน IET ที่นับได้อีกด้วย พวกมันไม่สามารถใช้แทนกันได้อย่างน้อยก็ไม่ใช่จากมุมมองทั้งหมด

หากคุณมีรายการ <T> คุณจะรับประกันได้ว่าวัตถุนี้ใช้วิธีการและคุณสมบัติที่จำเป็นในการใช้งานโดย ICollection <T> และ IEnumerable <T> อินเตอร์เฟส คอมไพเลอร์รู้และคุณได้รับอนุญาตให้โยนพวกเขา "ลง" เพื่อ ICollection <T> หรือ IEnumerable <T> โดยปริยาย อย่างไรก็ตามหากคุณมี ICollection <T> คุณต้องตรวจสอบอย่างชัดเจนในรหัสของคุณก่อนว่ามันเป็นรายการ <T> หรืออย่างอื่นบางทีพจนานุกรม <T> (โดยที่ T คือKeyValuePair ) ก่อนที่จะส่งไปยังสิ่งที่คุณ ความต้องการ.

คุณรู้ว่า ICollection ขยายจำนวน IEnumerable ดังนั้นคุณสามารถแปลงมันเป็น IEnumerable แต่ถ้าคุณมีเพียง IEnumerable อีกครั้งคุณจะไม่รับประกันว่ามันเป็น List อาจเป็นได้ แต่อาจเป็นอย่างอื่น คุณควรคาดหวังข้อยกเว้นการส่งที่ไม่ถูกต้องหากคุณพยายามส่งรายการ <T> ไปยังพจนานุกรม <T>

ดังนั้นพวกเขาจะไม่ "ใช้แทนกันได้"

นอกจากนี้ยังมีอินเทอร์เฟซทั่วไปให้ตรวจสอบสิ่งที่คุณสามารถหาได้ในSystem.Collections.Generic namespace

แก้ไข: เกี่ยวกับความคิดเห็นของคุณไม่มีการลงโทษประสิทธิภาพหากคุณใช้รายการ <T> หรือหนึ่งในอินเตอร์เฟสที่ใช้ คุณยังจะต้องสร้างวัตถุใหม่ลองดูรหัสต่อไปนี้:

List<T> list = new List<T>();
ICollection<T> myColl = list;
IEnumerable<T> myEnum = list;

รายการ , myCollและMyEnumชี้ไปที่วัตถุเดียวกัน ไม่ว่าคุณจะประกาศเป็นรายการหรือ ICollection หรือ IEnumerable ฉันยังต้องการให้โปรแกรมสร้างรายการ ฉันน่าจะเขียนสิ่งนี้:

ICollection<T> myColl = new List<T>();

myColl , ที่รันไทม์ยังคงเป็นรายการ

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

ลองจินตนาการว่าสิ่งเดียวที่เมธอด "PerformOperation" ต้องการคือการระบุองค์ประกอบทำงานและออกบางอย่างในกรณีที่คุณไม่ต้องการวิธีการนับร้อยที่มีอยู่ในรายการ <T> คุณต้องการเพียงสิ่งที่มีอยู่ใน IEnumerable <T > ดังนั้นควรใช้สิ่งต่อไปนี้:

public void PerformOperation(IEnumerable<T> myEnumeration) { ... }

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

หากในทางตรงกันข้ามคุณระบุว่าคุณต้องการรายการที่ชัดเจน <T> (และแม้ว่ามันจะไม่ค่อยเกิดขึ้นในชีวิตจริง แต่ก็อาจเกิดขึ้นได้) คุณและนักพัฒนาอื่น ๆ รู้ว่ามันต้องเป็นรายการหรือการสืบทอดคลาสอื่น จากรายการ


ก่อนอื่นต้องขอขอบคุณ ตอนนี้ประเด็นที่น่าเป็นห่วงคือวิธีการตัดสินใจเลือกใช้ เนื่องจากรายการ <T> ใช้ทั้งสองอินเทอร์เฟซทำไมไม่ใช้ในทุก ๆ ที่ที่จำเป็นต้องใช้ IEnumerable หรือ ICollection การใช้รายการจะมีผลกระทบกับประสิทธิภาพหรือไม่ โปรดแก้ไขคำตอบของคุณเพื่อตอบข้อกังวลเหล่านี้
Pankaj Upadhyay

ฉันแก้ไขเพื่อตอบคำถามประสิทธิภาพของคุณ
Jalayn

+1 แต่ฉันจะเพิ่มว่าในกรณีที่ไม่ค่อยเกิดขึ้นซึ่งคุณจำเป็นต้องใช้เพื่อส่งรายการไปยังวิธีหนึ่งคุณควรใช้IListแทนListการประกาศวิธี
Konamiman

@Konamiman - ขึ้นอยู่กับว่าคุณต้องการฟังก์ชั่นที่เฉพาะเจาะจงเช่นList<> ไม่เปิดเผยว่า .AddRange()IList<>
Bobson

6

ดูได้ที่หน้า MSDN สำหรับICollectionและIEnumerable

ในแง่ที่เป็นนามธรรมนี่คือวิธีที่ฉันเข้าใจสิ่งเหล่านี้

IEnumerable คือสิ่งใด ๆ ที่สามารถระบุได้นั่นคือวนซ้ำแล้วซ้ำอีก ไม่ได้แปลว่า 'สะสม' ตัวอย่างเช่นIQueryableใช้ IEnumerable และไม่ใช่คอลเล็กชัน แต่เป็นสิ่งที่สามารถสอบถามเพื่อส่งคืนวัตถุได้ ในการใช้ IEnumerable วัตถุจะต้องสามารถส่งคืนวัตถุเมื่อถูกสอบถามเท่านั้น ฉันอาจจะบอกว่าฉันมีงานนับไม่ถ้วนที่ฉันจะทำวันนี้ (ไม่ใช่รายการเพราะฉันยังไม่ได้เขียนหรือกำหนดสูตร แต่ฉันบอกได้เลยว่าฉันจะทำอะไรตอนนี้และ ถ้าคุณถาม 'แล้ว' ฉันจะสามารถบอกงานต่อไปนี้ให้คุณ)

ICollection นั้นเป็นรูปธรรมมากกว่า IEnumerable ข้อแตกต่างที่สำคัญคือคอลเล็กชันรู้จำนวนไอเท็มที่มี ในการคำนวณจำนวนไอเท็มที่มีอยู่ใน Enumerable คุณจะวนซ้ำอย่างมีประสิทธิภาพและนับมันได้:

ฉัน: พวกคุณมีของอยู่ในตัวคุณกี่รายการ

นับได้: ฉันไม่รู้จริงๆ นี่คือหนึ่งรายการ ฉันมีอันอื่นนั่นคือสองอัน และอีกอัน, นั่นคือสาม ... และอีกอัน ... ตกลงนั่นคือ 2382 ไม่มีรายการอีกแล้วดังนั้นฉันจึงได้ 2382 อย่าถามฉันอีกเพราะฉันจะต้องผ่านพวกเขาทั้งหมดอีกครั้ง

ชุดสะสม: ฉันมี 2382 รายการ ฉันรู้แล้วว่า

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

ในความคิดของฉันความแตกต่างระหว่างการนับและการรวบรวมมีขนาดใหญ่กว่าความแตกต่างระหว่างการรวบรวมและรายการ ในความเป็นจริงฉันกำลังดิ้นรนที่จะคิดถึงความแตกต่างที่เป็นประโยชน์ระหว่างการเก็บและรายการ แต่ฉันเชื่อว่ารายการมีวิธีการที่ดีกว่าสำหรับการค้นหาและการสั่งซื้อ

ประเภทอื่น ๆ ได้แก่ การเก็บQueueและเช่นเดียวกับStackDictionary

ชื่อประเภทเหล่านี้มีประโยชน์มาก - คุณสามารถนึกถึงคิวและสแต็กเป็นคู่หูในโลกแห่งความจริงและพิจารณาความแตกต่างที่คุณอาจมีต่อรายการ


"ฉันกำลังดิ้นรนที่จะคิดถึงความแตกต่างที่เป็นไปได้ระหว่างคอลเลคชั่นและลิสต์"ในคำตอบของคุณคุณตอบด้วยตนเอง Listเป็นICollectionแต่ICollectionไม่เสมอList( Queue, Stack, Dictionary, ... )
สตีเว่น Jeuris

@ สตีเว่นมันเป็นคำตอบที่ท่องเที่ยวมาก ฉันยอมรับว่านี่เป็นความแตกต่างที่สำคัญ แต่ฉันจะไม่เรียกมันว่าเป็นความแตกต่างที่ใช้งานได้จริง ผู้ใช้มีความหมายอย่างไร
Kirk Broadhurst

นั่นง่ายมาก! :) Queue<int> queue = (Queue<int>)list;จะโยนInvalidCastExceptionเมื่อไม่ได้เป็นlist Queue<int>ความแตกต่างระหว่างคิวและรายการอยู่นอกขอบเขตสำหรับคำถามนี้
Steven Jeuris

ไม่ใช่สิ่งสำคัญของ IEnumerable ที่สามารถส่งคืนรายการปัจจุบันและรายการถัดไป - คุณเรียงลำดับของการอ้างถึง แต่ไม่ได้พูดอย่างชัดเจน โดยพื้นฐานแล้วสิ่งที่ใช้ IEnumerable เพียงอย่างเดียวไม่สามารถส่งคืนรายการของสมาชิกได้เมื่อทำการสอบถาม - เฉพาะรายการปัจจุบันและรายการถัดไป
cori

@cori นั่นเป็นวิธีที่รวบรัดมากของการวางไว้ชัดเจนกว่าคำตอบของฉัน
Kirk Broadhurst

-1

IQueryable:

แบบสอบถามจะไม่ถูกดำเนินการจนกว่าจะวนซ้ำรายการจริง ๆ โดยอาจทำ. ToList ()

IEnumerable:

รายการไปข้างหน้าเท่านั้น คุณไม่สามารถไปถึง "รายการ 4" โดยไม่ผ่านรายการ 0-3 รายการแบบอ่านอย่างเดียวคุณไม่สามารถเพิ่มหรือลบออกได้ ยังอาจใช้การดำเนินการรอการตัดบัญชี

IList:

เข้าถึงแบบสุ่มไปยังรายการทั้งหมดในหน่วยความจำรองรับการเพิ่มและลบ

ICollection:

อยู่ระหว่าง IEnumerable และ IList "ดีที่สุด" คืออะไรขึ้นอยู่กับความต้องการของคุณ โดยทั่วไปแม้ว่า IEnumerable จะ "ดีพอ" ถ้าคุณต้องการแสดงรายการเท่านั้น อย่างน้อยก็ให้ใช้ตัวแปรทั่วไปเสมอ


คำตอบนี้ดูเหมือนจะไม่เพิ่มสิ่งที่มีค่ามากกว่าสิ่งที่โพสต์ไว้แล้วในคำตอบก่อนหน้า
gnat

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