ฉันเคยเห็นพวกเขาใช้ในรูปแบบเดียวกันมากมายและฉันกังวลว่าฉันกำลังจะไปตามเส้นทางในการออกแบบที่ไม่สามารถย้อนกลับได้หากฉันไม่เข้าใจสิ่งนี้ให้ดีขึ้น นอกจากนี้ฉันกำลังใช้. NET
ฉันเคยเห็นพวกเขาใช้ในรูปแบบเดียวกันมากมายและฉันกังวลว่าฉันกำลังจะไปตามเส้นทางในการออกแบบที่ไม่สามารถย้อนกลับได้หากฉันไม่เข้าใจสิ่งนี้ให้ดีขึ้น นอกจากนี้ฉันกำลังใช้. NET
คำตอบ:
Collection<T>
เป็นกระดาษห่อหุ้มที่ปรับแต่งIList<T>
ได้ แม้ว่าIList<T>
จะไม่ได้ปิดผนึก แต่ก็ไม่มีจุดปรับแต่งใด ๆ Collection<T>
โดยค่าเริ่มต้นเมธอดจะถูกมอบหมายให้เป็นIList<T>
วิธีมาตรฐานแต่สามารถแทนที่ได้อย่างง่ายดายเพื่อทำสิ่งที่คุณต้องการ นอกจากนี้ยังเป็นไปได้ที่จะวางสายเหตุการณ์ภายในCollection<T>
ที่ฉันไม่เชื่อว่าจะทำได้ด้วย IList
ในระยะสั้นมันง่ายกว่ามากที่จะขยายหลังจากความจริงซึ่งอาจหมายถึงการปรับโครงสร้างใหม่น้อยกว่ามาก
IList
, IList<T>
, List<T>
ฯลฯ ในระยะสั้นที่คุณมีความคิดว่ามันจะถูกเรียกว่าไม่มี Polymorphism แก้ไขสิ่งนี้
ObservableCollection<T>
ตัวอย่างที่วิธีการถูกลบล้างเพื่อแจ้งให้ทราบเกี่ยวกับการเปลี่ยนแปลง
ใน 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
:
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);
เลือกแนวคิดที่คุณต้องการจากนั้นใช้คลาสที่ตรงกัน
ICollection<T>
และIList<T>
. การใช้งานคอนกรีตที่แตกต่างกันอาจมีพฤติกรรมแตกต่างกัน ตัวอย่างเช่นหากคุณเข้าถึงList<T>
ผ่านIEnumerable<T>
อินเทอร์เฟซคุณจะไม่มีทางเพิ่มลบเรียงลำดับหรือนับรายการในรายการได้
List<T>
มีไว้สำหรับใช้ภายในรหัสแอปพลิเคชัน คุณควรหลีกเลี่ยงการเขียน API สาธารณะที่ยอมรับหรือส่งคืนList<T>
(พิจารณาใช้ซูเปอร์คลาสหรืออินเทอร์เฟซการรวบรวมแทน)
Collection<T>
ทำหน้าที่เป็นคลาสพื้นฐานสำหรับคอลเล็กชันแบบกำหนดเอง (แม้ว่าจะสามารถใช้ได้โดยตรง)
พิจารณาใช้Collection<T>
ในโค้ดของคุณเว้นแต่จะมีคุณสมบัติเฉพาะList<T>
ที่คุณต้องการ
ข้างต้นเป็นเพียงคำแนะนำ
[ดัดแปลงจาก: Framework Design Guidelines, Second Edition]
Dictionary<string, List<string>>
ส่งคืนList<string>
นั้นใช้ได้ดีเนื่องจากสถานะของพจนานุกรมจะสรุปเฉพาะข้อมูลประจำตัวของรายการในนั้นแทนที่จะเป็นเนื้อหา
List<T>
เป็นภาชนะเห็นบ่อยมากเพราะมันเป็นไปอย่างหลากหลายมาก (มีจำนวนมากของวิธีการที่มีประโยชน์เช่นSort
, Find
ฯลฯ ) - แต่ไม่เคยมีใครจุดขยายถ้าคุณต้องการที่จะแทนที่ใด ๆ ของพฤติกรรม (รายการตรวจสอบแทรกตัวอย่าง)
Collection<T>
เป็นห่อหุ้มรอบ ๆIList<T>
(ผิดนัดList<T>
) - มันมีจุดส่วนขยาย ( virtual
วิธีการ) Find
แต่ไม่เป็นวิธีการสนับสนุนมากมายเช่น เนื่องจากทิศทางจึงช้ากว่าเล็กน้อยList<T>
แต่ไม่มากนัก
ด้วย LINQ, วิธีการพิเศษในการList<T>
กลายเป็นความสำคัญน้อยกว่าตั้งแต่ LINQ เพื่อวัตถุที่มีแนวโน้มที่จะให้พวกเขาอยู่แล้ว ... ตัวอย่างเช่นFirst(pred)
, OrderBy(...)
ฯลฯ
รายการเร็วขึ้น
ทำตัวอย่าง
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%
รายการแสดงถึงคอลเล็กชันที่ลำดับของรายการมีความสำคัญ นอกจากนี้ยังสนับสนุนวิธีการจัดเรียงและค้นหา คอลเล็กชันเป็นโครงสร้างข้อมูลทั่วไปซึ่งทำให้สมมติฐานเกี่ยวกับข้อมูลน้อยลงและยังสนับสนุนวิธีการจัดการน้อยลง หากคุณต้องการเปิดเผยโครงสร้างข้อมูลที่กำหนดเองคุณควรขยายคอลเล็กชัน หากคุณต้องการจัดการข้อมูลโดยไม่เปิดเผยโครงสร้างข้อมูลรายการน่าจะเป็นวิธีที่สะดวกกว่าในการไป
นี่เป็นหนึ่งในคำถามระดับประถมศึกษา คอลเลกชันของ T เป็นนามธรรม อาจมีการใช้งานเริ่มต้น (ฉันไม่ใช่. net / c # guy) แต่คอลเล็กชันจะมีการใช้งานพื้นฐานเช่นเพิ่มลบทำซ้ำและอื่น ๆ
รายการ T หมายถึงข้อมูลเฉพาะบางอย่างเกี่ยวกับการดำเนินการเหล่านี้: การเพิ่มควรใช้เวลาคงที่การลบควรใช้เวลาตามสัดส่วนกับจำนวนองค์ประกอบ getfirst ควรเป็นเวลาที่สอดคล้องกัน โดยทั่วไปรายการคือคอลเล็กชันประเภทหนึ่ง แต่คอลเล็กชันไม่จำเป็นต้องเป็นรายการประเภทหนึ่ง
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 มีคลาสที่สามารถใช้เป็นคอลเลกชันในโมเดลอ็อบเจ็กต์ของไลบรารีที่ใช้ซ้ำได้ใช้คลาสเหล่านี้เมื่อคุณสมบัติหรือเมธอดส่งคืนคอลเล็กชัน"
อินเทอร์เฟซทั้งหมดเหล่านี้สืบทอดมาIEnumerable
ซึ่งคุณควรแน่ใจว่าคุณเข้าใจ โดยพื้นฐานแล้วอินเทอร์เฟซนั้นให้คุณใช้คลาสในคำสั่ง foreach (ใน C #)
ICollection
เป็นอินเทอร์เฟซพื้นฐานที่สุดที่คุณระบุไว้ เป็นอินเทอร์เฟซที่แจกแจงได้ซึ่งรองรับCount
และที่เกี่ยวกับมันIList
คือทุกอย่างที่ICollection
เป็นอยู่ แต่ยังรองรับการเพิ่มและลบรายการการเรียกค้นรายการตามดัชนี ฯลฯ เป็นอินเทอร์เฟซที่ใช้บ่อยที่สุดสำหรับ "รายการวัตถุ" ซึ่งฉันรู้ว่าคลุมเครือIQueryable
เป็นอินเทอร์เฟซที่นับได้ซึ่งรองรับ LINQ คุณสามารถสร้างIQueryable
จาก IList และใช้ LINQ เป็น Objects ได้ตลอดเวลา แต่คุณยังพบว่าIQueryable
ใช้สำหรับการดำเนินการคำสั่ง SQL ที่เลื่อนออกไปใน LINQ เป็น SQL และ LINQ ไปยังเอนทิตีIDictionary
เป็นสัตว์ที่แตกต่างกันในแง่ที่ว่ามันเป็นการจับคู่คีย์เฉพาะกับค่า นอกจากนี้ยังสามารถระบุได้ว่าคุณสามารถระบุคู่คีย์ / ค่าได้ แต่มิฉะนั้นจะมีจุดประสงค์ที่แตกต่างจากที่คุณระบุไว้ตามที่ 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"!?!
ทั้งสองใช้อินเทอร์เฟซเดียวกันดังนั้นจึงทำงานในลักษณะเดียวกัน บางทีอาจมีการใช้งานภายในที่แตกต่างกัน แต่จะต้องมีการทดสอบ
ความแตกต่างที่แท้จริงเพียงอย่างเดียวที่ฉันเห็นคือเนมสเปซและความจริงที่Collection<T>
มีเครื่องหมายComVisibleAttribute(false)
ดังนั้นโค้ด COM จึงไม่สามารถใช้งานได้
นอกเหนือจาก 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() *