อะไรคือความแตกต่างระหว่าง List (of T) และ Collection (of T)?


96

ฉันเคยเห็นพวกเขาใช้ในรูปแบบเดียวกันมากมายและฉันกังวลว่าฉันกำลังจะไปตามเส้นทางในการออกแบบที่ไม่สามารถย้อนกลับได้หากฉันไม่เข้าใจสิ่งนี้ให้ดีขึ้น นอกจากนี้ฉันกำลังใช้. NET

คำตอบ:


50

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

ในระยะสั้นมันง่ายกว่ามากที่จะขยายหลังจากความจริงซึ่งอาจหมายถึงการปรับโครงสร้างใหม่น้อยกว่ามาก


@Marc Gravell, @Adam Lassek: เราไม่สามารถทำสิ่งเดียวกันกับรายการได้โดยซ่อนเมธอด InsertItem (... ) ด้วยโมฆะสาธารณะใหม่ InsertItem (... ) จากนั้นเรียกฐาน InsertItem (.. .) จากภายใน? มันคงยังไม่ผิดสัญญา (ชื่อคือ 'แทรก' ในรายการ แต่ถึงกระนั้นก็ตาม) อะไรคือเรื่องใหญ่ในการติด Collections <T>?
DeeStackOverflow

4
@DeeStackOverflow - เพราะวิธีการหลบซ่อนตัวอยู่จะไม่ถูกนำมาใช้โดยรหัสที่ใช้ API ที่แตกต่างกัน - คือสิ่งที่จะมองหาIList, IList<T>, List<T>ฯลฯ ในระยะสั้นที่คุณมีความคิดว่ามันจะถูกเรียกว่าไม่มี Polymorphism แก้ไขสิ่งนี้
Marc Gravell

1
@AdamLassek: คุณอาจต้องการเพิ่มคำตอบของคุณเกี่ยวกับObservableCollection<T>ตัวอย่างที่วิธีการถูกลบล้างเพื่อแจ้งให้ทราบเกี่ยวกับการเปลี่ยนแปลง
Kiran Challa

92

ใน C # มีแนวคิดสามประการในการแทนถุงวัตถุ ตามลำดับของคุณสมบัติที่เพิ่มขึ้น ได้แก่ :

  • นับได้ - ไม่เรียงลำดับและไม่สามารถปรับเปลี่ยนได้
  • คอลเลกชัน - สามารถเพิ่ม / ลบรายการ
  • รายการ - อนุญาตให้รายการมีคำสั่งซื้อ (เข้าถึงและลบตามดัชนี)

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

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

รายการคือชุดของวัตถุตามลำดับ คุณสามารถเรียงลำดับรายการเข้าถึงรายการตามดัชนีลบรายการตามดัชนี

ในความเป็นจริงเมื่อดูอินเทอร์เฟซสำหรับสิ่งเหล่านี้พวกเขาจะสร้างกันและกัน:

  • interface IEnumerable<T>

    • GetEnumeration<T>
  • interface ICollection<T> : IEnumerable<T>

    • Add
    • Remove
    • Clear
    • Count
  • interface IList<T> = ICollection<T>

    • Insert
    • IndexOf
    • RemoveAt

เมื่อประกาศตัวแปรหรือพารามิเตอร์วิธีการคุณควรเลือกใช้

  • IEnumerable
  • ICollection
  • IList

ตามแนวความคิดคุณต้องทำกับชุดของวัตถุ

หากคุณต้องการเพียงแค่สามารถทำบางสิ่งกับทุกวัตถุในรายการคุณจะต้องIEnumerable:

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}

คุณไม่สนใจว่าผู้ใช้จะถูกเก็บไว้ในList<T>, Collection<T>, Array<T>หรือสิ่งอื่นใด คุณต้องมีIEnumerable<T>อินเทอร์เฟซเท่านั้น

หากคุณต้องการเพิ่มลบหรือนับรายการในชุดให้ใช้คอลเลคชัน :

ICollection<User> users = new Collection<User>();
users.Add(new User());

หากคุณสนใจเกี่ยวกับลำดับการจัดเรียงและต้องการให้ลำดับถูกต้องให้ใช้รายการ :

IList<User> users = FetchUsers(db);

ในรูปแบบแผนภูมิ:

| Feature                | IEnumerable<T> | ICollection<T> | IList<T> |
|------------------------|----------------|----------------|----------|
| Enumerating items      | X              | X              | X        |
|                        |                |                |          |
| Adding items           |                | X              | X        |
| Removing items         |                | X              | X        |
| Count of items         |                | X              | X        |
|                        |                |                |          |
| Accessing by index     |                |                | X        |
| Removing by indexx     |                |                | X        |
| Getting index of item  |                |                | X        |

List<T>และCollection<T>ในSystem.Collections.Genericสองชั้นเรียนที่ใช้เชื่อมต่อเหล่านี้; แต่ไม่ใช่คลาสเดียว:

  • ConcurrentBag<T>เป็นถุงวัตถุตามสั่ง ( IEnumerable<T>)
  • LinkedList<T>เป็นกระเป๋าที่คุณไม่ได้รับอนุญาตให้เข้าถึงรายการโดย index ( ICollection); แต่คุณสามารถเพิ่มและลบรายการออกจากคอลเลกชันได้ตามอำเภอใจ
  • SynchronizedCollection<T> ในคอลเลกชันที่สั่งซื้อซึ่งคุณสามารถเพิ่ม / ลบรายการตามดัชนี

คุณจึงสามารถเปลี่ยนแปลงได้อย่างง่ายดาย:

IEnumerable<User> users = new SynchronizedCollection<User>();

SaveEveryUser(users);

tl; dr

  • นับได้ - เข้าถึงรายการไม่เรียงลำดับไม่สามารถแก้ไขได้
  • คอลเลกชัน - สามารถแก้ไขได้ (เพิ่มลบนับ)
  • รายการ - สามารถเข้าถึงโดยดัชนี

เลือกแนวคิดที่คุณต้องการจากนั้นใช้คลาสที่ตรงกัน


11
OP ถามเกี่ยวกับประเภทคอนกรีตและคุณได้เปรียบเทียบอินเทอร์เฟซแล้ว ประเภทคอนกรีตคอลเลกชัน <T> ใช้ IList <T> และมีการเข้าถึงโดยความสามารถของดัชนี
JJS

2
คำตอบนั้นดี แต่คลาดเคลื่อนไปจากคำถามไม่สามารถตอบสนองคำตอบของคุณสำหรับคลาส Collection <T> และ List <T> ได้ฉันหมายถึงจากคำถามที่คาดหวังหากฉันพยายามตรวจสอบประเด็นของคุณพวกเขาก็ไม่ได้ให้เหตุผล สำหรับคำตอบวัตถุประสงค์ทั่วไปคุณอาจคิดถูกว่าคอลเลกชันไม่ได้ถูกเรียงลำดับดังนั้นจึงไม่มีการจัดทำดัชนี แต่มีการเรียงลำดับรายการดังนั้นการแทรกจึงเป็นไปได้ที่ดัชนีหนึ่ง ๆ
Kylo Ren

จะเป็นอย่างไรถ้าฉันมีคุณสมบัติจาก ICollection <T> และการแก้ปัญหาและค้นหาความเป็นไปได้

2
หากมีการจัดลำดับรายการและคอลเล็กชันไม่เป็นระเบียบนั่นจะเป็นความแตกต่างในการทำงานอย่างมากที่จะแนะนำผู้เรียนใหม่ (เช่นฉัน) ให้เลือกได้อย่างง่ายดาย แต่เดี๋ยวก่อนทำไมคุณถึงบอกว่าคอลเลกชันไม่มีใบสั่ง? มันมีวิธีIndexOf ()และRemoveAt ()ดังนั้นจึงเป็นคำสั่งใช่หรือไม่? ฉันพลาดอะไรบางอย่างที่นี่?
RayLuo

1
@RayLuo ฉันหมายถึงโดยเฉพาะICollection<T>และIList<T>. การใช้งานคอนกรีตที่แตกต่างกันอาจมีพฤติกรรมแตกต่างกัน ตัวอย่างเช่นหากคุณเข้าถึงList<T>ผ่านIEnumerable<T>อินเทอร์เฟซคุณจะไม่มีทางเพิ่มลบเรียงลำดับหรือนับรายการในรายการได้
Ian Boyd

44

List<T>มีไว้สำหรับใช้ภายในรหัสแอปพลิเคชัน คุณควรหลีกเลี่ยงการเขียน API สาธารณะที่ยอมรับหรือส่งคืนList<T>(พิจารณาใช้ซูเปอร์คลาสหรืออินเทอร์เฟซการรวบรวมแทน)

Collection<T> ทำหน้าที่เป็นคลาสพื้นฐานสำหรับคอลเล็กชันแบบกำหนดเอง (แม้ว่าจะสามารถใช้ได้โดยตรง)

พิจารณาใช้Collection<T>ในโค้ดของคุณเว้นแต่จะมีคุณสมบัติเฉพาะList<T>ที่คุณต้องการ

ข้างต้นเป็นเพียงคำแนะนำ

[ดัดแปลงจาก: Framework Design Guidelines, Second Edition]


เป็นที่น่าสังเกตว่าประเภทที่ใช้อ็อบเจ็กต์ที่เปลี่ยนแปลงได้ทุกชนิดในการห่อหุ้มสถานะของตัวเองควรหลีกเลี่ยงการส่งคืนอ็อบเจ็กต์ประเภทดังกล่าวเว้นแต่ว่าอ็อบเจ็กต์ที่เป็นปัญหาจะมีวิธีการแจ้งเจ้าของเมื่อมีการกลายพันธุ์หรือชื่อของเมธอดที่ส่งคืน แสดงนัยอย่างชัดเจนว่ากำลังส่งคืนอินสแตนซ์ใหม่ โปรดทราบว่าเช่นการDictionary<string, List<string>>ส่งคืนList<string>นั้นใช้ได้ดีเนื่องจากสถานะของพจนานุกรมจะสรุปเฉพาะข้อมูลประจำตัวของรายการในนั้นแทนที่จะเป็นเนื้อหา
supercat

37

List<T>เป็นภาชนะเห็นบ่อยมากเพราะมันเป็นไปอย่างหลากหลายมาก (มีจำนวนมากของวิธีการที่มีประโยชน์เช่นSort, Findฯลฯ ) - แต่ไม่เคยมีใครจุดขยายถ้าคุณต้องการที่จะแทนที่ใด ๆ ของพฤติกรรม (รายการตรวจสอบแทรกตัวอย่าง)

Collection<T>เป็นห่อหุ้มรอบ ๆIList<T>(ผิดนัดList<T>) - มันมีจุดส่วนขยาย ( virtualวิธีการ) Findแต่ไม่เป็นวิธีการสนับสนุนมากมายเช่น เนื่องจากทิศทางจึงช้ากว่าเล็กน้อยList<T>แต่ไม่มากนัก

ด้วย LINQ, วิธีการพิเศษในการList<T>กลายเป็นความสำคัญน้อยกว่าตั้งแต่ LINQ เพื่อวัตถุที่มีแนวโน้มที่จะให้พวกเขาอยู่แล้ว ... ตัวอย่างเช่นFirst(pred), OrderBy(...)ฯลฯ


6
คอลเลกชัน <T> ไม่มีเมธอด foreach แม้ใน Linq-to-Objects
tuinstoel

7
@tuinstoel - แต่มันเป็นเรื่องเล็กน้อยที่จะเพิ่ม
Marc Gravell

12

รายการเร็วขึ้น

ทำตัวอย่าง

private void button1_Click(object sender, EventArgs e)
{
  Collection<long> c = new Collection<long>();
  Stopwatch s = new Stopwatch();
  s.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    c.Add(i);
  }
  s.Stop();
  MessageBox.Show("collect " + s.ElapsedMilliseconds.ToString());

  List<long> l = new List<long>();
  Stopwatch s2 = new Stopwatch();
  s2.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    l.Add(i);
  }
  s2.Stop();
  MessageBox.Show("lis " + s2.ElapsedMilliseconds.ToString());


}

บนเครื่องของฉันList<>เร็วกว่าเกือบสองเท่า

แก้ไข

ฉันไม่เข้าใจว่าทำไมผู้คนถึงลงคะแนนสิ่งนี้ ทั้งในเครื่องที่ทำงานและเครื่องที่บ้านรหัสรายการ <> เร็วขึ้น 80%


1
เร็วขึ้นอย่างไร? ค้นหา? แทรก? กำจัด? ค้นหา? ทำไมถึงเร็วกว่า?
Doug T.

17
ลิสต์มีตัวอักษรให้พิมพ์น้อยกว่า Collection :)
D'Arcy Rittich

1
การรวบรวมมีวิธีการน้อยกว่า ดังนั้นจึงเร็วกว่า QED (ล้อเล่นฉันไม่หลอก)
เรย์

2
ลองใช้บนเครื่องแล้วรายการเร็วขึ้นประมาณ 20% จะมีความสนใจในการอภิปรายเกี่ยวกับสาเหตุนี้ บางทีรายการจะดีกว่าเมื่อจัดสรรหน่วยความจำ
Ray

10
วิธีการของรายการไม่สามารถสืบทอดได้ดังนั้นจึงไม่มีการตรวจสอบว่ามีการสืบทอดหรือไม่ วิธีการเก็บรวบรวมสามารถสืบทอดได้ ข้อดีคือคุณสามารถใช้ Collection เป็นคลาสพื้นฐานเพื่อสืบทอดและสร้างคอลเล็กชันแบบกำหนดเองได้
Richard Gadsden

11

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


4

นี่เป็นหนึ่งในคำถามระดับประถมศึกษา คอลเลกชันของ T เป็นนามธรรม อาจมีการใช้งานเริ่มต้น (ฉันไม่ใช่. net / c # guy) แต่คอลเล็กชันจะมีการใช้งานพื้นฐานเช่นเพิ่มลบทำซ้ำและอื่น ๆ

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


4

Hanselman Speaks : " Collection<T>ดูเหมือนรายการและยังมีอยู่List<T>ภายในทุก ๆ วิธีการเดียวที่มอบหมายให้กับภายในList<T>ประกอบด้วยคุณสมบัติที่ได้รับการป้องกันที่เปิดเผยList<T>"

แก้ไข: Collection<T>ไม่มีอยู่ใน System.Generic.Collections .NET 3.5 หากคุณย้ายจาก. NET 2.0 เป็น 3.5 คุณจะต้องเปลี่ยนรหัสบางอย่างหากคุณใช้Collection<T>วัตถุจำนวนมากเว้นแต่ฉันจะพลาดสิ่งที่ชัดเจน ...

แก้ไข 2: Collection<T>ขณะนี้อยู่ในเนมสเปซ System.Collections.ObjectModel ใน. NET 3.5 ไฟล์ช่วยเหลือระบุว่า:

"เนมสเปซ System.Collections.ObjectModel มีคลาสที่สามารถใช้เป็นคอลเลกชันในโมเดลอ็อบเจ็กต์ของไลบรารีที่ใช้ซ้ำได้ใช้คลาสเหล่านี้เมื่อคุณสมบัติหรือเมธอดส่งคืนคอลเล็กชัน"


4

อินเทอร์เฟซทั้งหมดเหล่านี้สืบทอดมาIEnumerableซึ่งคุณควรแน่ใจว่าคุณเข้าใจ โดยพื้นฐานแล้วอินเทอร์เฟซนั้นให้คุณใช้คลาสในคำสั่ง foreach (ใน C #)

  • ICollectionเป็นอินเทอร์เฟซพื้นฐานที่สุดที่คุณระบุไว้ เป็นอินเทอร์เฟซที่แจกแจงได้ซึ่งรองรับCountและที่เกี่ยวกับมัน
  • IListคือทุกอย่างที่ICollectionเป็นอยู่ แต่ยังรองรับการเพิ่มและลบรายการการเรียกค้นรายการตามดัชนี ฯลฯ เป็นอินเทอร์เฟซที่ใช้บ่อยที่สุดสำหรับ "รายการวัตถุ" ซึ่งฉันรู้ว่าคลุมเครือ
  • IQueryableเป็นอินเทอร์เฟซที่นับได้ซึ่งรองรับ LINQ คุณสามารถสร้างIQueryableจาก IList และใช้ LINQ เป็น Objects ได้ตลอดเวลา แต่คุณยังพบว่าIQueryableใช้สำหรับการดำเนินการคำสั่ง SQL ที่เลื่อนออกไปใน LINQ เป็น SQL และ LINQ ไปยังเอนทิตี
  • IDictionaryเป็นสัตว์ที่แตกต่างกันในแง่ที่ว่ามันเป็นการจับคู่คีย์เฉพาะกับค่า นอกจากนี้ยังสามารถระบุได้ว่าคุณสามารถระบุคู่คีย์ / ค่าได้ แต่มิฉะนั้นจะมีจุดประสงค์ที่แตกต่างจากที่คุณระบุไว้

ICollection รองรับการเพิ่ม / ลบ / ล้าง: msdn.microsoft.com/en-us/library/…
amnesia

4

ตามที่ MSDN รายการ (จาก T) .Add คือ "O (n) ดำเนินการ" (เมื่อ "ความจุ" เกิน) ในขณะที่คอลเลกชัน (จาก T) .Add เป็นเสมอ "มี O (1) ดำเนินการ" สิ่งนี้จะเข้าใจได้หากใช้รายการโดยใช้อาร์เรย์และรวบรวมรายการที่เชื่อมโยง อย่างไรก็ตามหากเป็นเช่นนั้นเราคาดว่า Collection (Of T) รายการจะเป็น "การดำเนินการ O (n)" แต่ - มัน - ไม่ใช่ !?! คอลเลกชัน (ของ T) รายการคือ "การดำเนินการ O (1)" เช่นเดียวกับรายการ (ของ T) รายการ

ยิ่งไปกว่านั้น "tuinstoel" ของ "29 ธ.ค. 51 เวลา 22:31" โพสต์ด้านบนอ้างว่าการทดสอบความเร็วแสดงรายการ (ของ T) เพิ่มให้เร็วกว่าคอลเลคชัน (ของ T) เพิ่มซึ่งฉันได้ทำซ้ำด้วย ลองและสตริง แม้ว่าฉันจะเร็วขึ้นเพียง ~ 33% เมื่อเทียบกับที่เขาอ้างว่า 80% ตาม MSDN แต่มันควรจะตรงกันข้ามและเป็นครั้งที่ "n"!?!


3

ทั้งสองใช้อินเทอร์เฟซเดียวกันดังนั้นจึงทำงานในลักษณะเดียวกัน บางทีอาจมีการใช้งานภายในที่แตกต่างกัน แต่จะต้องมีการทดสอบ

ความแตกต่างที่แท้จริงเพียงอย่างเดียวที่ฉันเห็นคือเนมสเปซและความจริงที่Collection<T>มีเครื่องหมายComVisibleAttribute(false)ดังนั้นโค้ด COM จึงไม่สามารถใช้งานได้


พวกเขาใช้อินเทอร์เฟซที่แตกต่างกัน - รายการ <T> ใช้ IList <T> โดยที่ Collection <T> ไม่มี
Bevan

@Bevan ลองใน c # ทั้งคู่ใช้อินเทอร์เฟซชุดเดียวกัน
Kylo Ren

1
นั่นเป็น @KyloRen เปลี่ยนแปลงที่น่าสนใจ - พวกเขาทำในขณะนี้ทั้งสองใช้ชุดเดียวกันของอินเตอร์เฟซ; นี่ไม่ใช่กรณีย้อนกลับไปในปี '08
Bevan

1
@ Bevan น่าสนใจ ไม่แน่ใจว่าอะไรเป็นสาเหตุของสองคลาสที่แตกต่างกันโดยหนึ่งคลาสมีวิธีพิเศษ
Kylo Ren

3

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

* = ปัจจุบัน
o = ปัจจุบันบางส่วน

การรวบรวมคุณสมบัติ / วิธี <T> รายการ <T>
----------------------------------------------
Add()                *              *
AddRange()                          *
AsReadOnly()                        *
BinarySearch()                      *
Capacity                            *
Clear()              *              *
Contains()           *              *
ConvertAll()                        *
CopyTo()             o              *
Count                *              *
Equals()             *              *
Exists()                            *
Find()                              *
FindAll()                           *
FindIndex()                         *
FindLast()                          *
FindLastIndex()                     *
ForEach()                           *
GetEnumerator()      *              *
GetHashCode()        *              *
GetRange()                          *
GetType()            *              *
IndexOf()            o              *
Insert()             *              *
InsertRange()                       *
Item()               *              *
LastIndexOf()                       *
New()                o              *
ReferenceEquals()    *              *
Remove()             *              *
RemoveAll()                         *
RemoveAt()           *              *
RemoveRange()                       *
Reverse()                           *
Sort()                              *
ToArray()                           *
ToString()           *              *
TrimExcess()                        *
TrueForAll()                        *
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.