Tôi đã thấy chúng được sử dụng theo nhiều cách giống nhau và tôi lo lắng rằng mình sắp đi vào con đường thiết kế không thể thay đổi nếu tôi không hiểu rõ hơn về điều này. Ngoài ra, tôi đang sử dụng .NET.
Tôi đã thấy chúng được sử dụng theo nhiều cách giống nhau và tôi lo lắng rằng mình sắp đi vào con đường thiết kế không thể thay đổi nếu tôi không hiểu rõ hơn về điều này. Ngoài ra, tôi đang sử dụng .NET.
Câu trả lời:
Collection<T>
là một trình bao bọc có thể tùy chỉnh xung quanh IList<T>
. Trong khiIList<T>
không được niêm phong, nó không cung cấp bất kỳ điểm tùy chỉnh nào. Collection<T>
Các phương thức của theo mặc định được ủy quyền cho các IList<T>
phương thức tiêu chuẩn , nhưng có thể dễ dàng bị ghi đè để làm những gì bạn muốn. Cũng có thể xâu chuỗi các sự kiện bên trong Collection<T>
mà tôi không tin là có thể được thực hiện với IList.
Nói tóm lại, việc gia hạn nó sau thực tế sẽ dễ dàng hơn nhiều, điều này có thể đồng nghĩa với việc ít tái cấu trúc hơn rất nhiều.
IList
, IList<T>
, List<T>
vv Trong ngắn hạn, bạn không có ý tưởng cho dù đó sẽ được gọi. Tính đa hình khắc phục điều này.
ObservableCollection<T>
làm ví dụ trong đó các phương thức được ghi đè để thông báo về các thay đổi.
Trong C #, có ba khái niệm để biểu diễn một túi các đối tượng. Để tăng các tính năng, chúng là:
Enumerable không có thứ tự. Bạn không thể thêm hoặc bớt các mục khỏi tập hợp. Bạn thậm chí không thể nhận được số lượng các mục trong bộ. Nó hoàn toàn cho phép bạn truy cập từng mục trong bộ, cái này đến cái khác.
Bộ sưu tập là một tập hợp có thể sửa đổi. Bạn có thể thêm và xóa các đối tượng khỏi tập hợp, bạn cũng có thể nhận được số lượng các mục trong tập hợp. Nhưng vẫn không có thứ tự, và bởi vì không có thứ tự: không có cách nào để truy cập một mục theo chỉ mục, cũng như không có cách nào để sắp xếp.
Danh sách là một tập hợp các đối tượng có thứ tự. Bạn có thể sắp xếp danh sách, truy cập các mục theo chỉ mục, xóa các mục theo chỉ mục.
Trên thực tế, khi nhìn vào các giao diện cho những thứ này, chúng xây dựng dựa trên nhau:
interface IEnumerable<T>
GetEnumeration<T>
interface ICollection<T> : IEnumerable<T>
Add
Remove
Clear
Count
interface IList<T> = ICollection<T>
Insert
IndexOf
RemoveAt
Khi khai báo các biến hoặc tham số phương thức, bạn nên chọn sử dụng
dựa trên khái niệm bạn cần làm với tập hợp các đối tượng.
Nếu bạn chỉ cần có thể thực hiện điều gì đó với mọi đối tượng trong danh sách, thì bạn chỉ cần IEnumerable
:
void SaveEveryUser(IEnumerable<User> users)
{
for User u in users
...
}
Bạn không quan tâm nếu người dùng được lưu giữ trong một List<T>
, Collection<T>
, Array<T>
hoặc bất cứ điều gì khác. Bạn chỉ cầnIEnumerable<T>
giao diện.
Nếu bạn cần có thể thêm, bớt hoặc đếm các mục trong một tập hợp, thì hãy sử dụng Bộ sưu tập :
ICollection<User> users = new Collection<User>();
users.Add(new User());
Nếu bạn quan tâm đến một thứ tự sắp xếp và cần thứ tự chính xác, thì hãy sử dụng Danh sách :
IList<User> users = FetchUsers(db);
Ở dạng biểu đồ:
| 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 |
Các List<T>
và Collection<T>
trong System.Collections.Generic
hai lớp mà thực hiện các giao diện; nhưng chúng không phải là những lớp duy nhất:
ConcurrentBag<T>
là một túi đồ vật có thứ tự ( IEnumerable<T>
)LinkedList<T>
là một túi mà bạn không được phép truy cập các mục theo index ( ICollection
); nhưng bạn có thể tùy ý thêm và bớt các mục khỏi bộ sưu tậpSynchronizedCollection<T>
trong một bộ sưu tập có thứ tự, nơi bạn có thể thêm / bớt các mục theo chỉ mụcVì vậy, bạn có thể dễ dàng thay đổi:
IEnumerable<User> users = new SynchronizedCollection<User>();
SaveEveryUser(users);
Chọn khái niệm bạn cần, sau đó sử dụng lớp đối sánh.
ICollection<T>
và IList<T>
. Các triển khai cụ thể khác nhau có thể hoạt động khác nhau. Ví dụ: nếu bạn truy cập một List<T>
thông qua IEnumerable<T>
giao diện của nó , thì bạn không có cách nào để thêm, xóa, sắp xếp hoặc đếm các mục trong danh sách.
List<T>
được thiết kế để sử dụng nội bộ trong mã ứng dụng. Bạn nên tránh viết các API công khai chấp nhận hoặc trả lạiList<T>
(thay vào đó hãy cân nhắc sử dụng lớp cha hoặc giao diện bộ sưu tập).
Collection<T>
phục vụ một lớp cơ sở cho các bộ sưu tập tùy chỉnh (mặc dù nó có thể được sử dụng trực tiếp).
Cân nhắc sử dụng Collection<T>
mã của bạn trừ khi có các tính năng cụ thể củaList<T>
mà bạn cần.
Trên đây chỉ là những khuyến nghị.
[Phỏng theo: Nguyên tắc thiết kế khung, Ấn bản thứ hai]
Dictionary<string, List<string>>
to return List<string>
là tốt, vì trạng thái của từ điển chỉ đóng gói danh tính của các danh sách trong đó, thay vì nội dung của chúng.
List<T>
là một thùng chứa rất thường thấy, vì nó rất linh hoạt (với nhiều phương pháp tiện dụng như Sort
,Find
v.v.) - nhưng không có điểm mở rộng nếu bạn muốn ghi đè bất kỳ hành vi nào (ví dụ: kiểm tra các mục trên chèn).
Collection<T>
là một trình bao bọc xung quanh bất kỳ IList<T>
(mặc định là List<T>
) - nó có các điểm mở rộng ( virtual
phương thức), nhưng không có nhiều phương thức hỗ trợ như Find
. Vì chuyển hướng, nó hơi chậm hơn List<T>
, nhưng không nhiều.
Với LINQ, các phương pháp bổ sung trong List<T>
trở nên ít quan trọng, vì LINQ-to-Đối tượng có xu hướng cung cấp cho họ anyway ... ví dụ First(pred)
, OrderBy(...)
vv
Danh sách nhanh hơn.
Làm ví dụ
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());
}
trên máy của tôi List<>
nhanh hơn gần như gấp đôi.
Biên tập
Tôi không hiểu tại sao mọi người lại phản đối điều này. Cả trên máy làm việc và máy nhà của tôi, mã List <> đều nhanh hơn 80%.
Danh sách đại diện cho một tập hợp mà thứ tự của các mục là quan trọng. Nó cũng hỗ trợ các phương pháp sắp xếp và tìm kiếm. Collection là một cấu trúc dữ liệu tổng quát hơn, tạo ra ít giả định hơn về dữ liệu và cũng hỗ trợ ít phương pháp để thao tác hơn. Nếu bạn muốn hiển thị cấu trúc dữ liệu tùy chỉnh, bạn có thể nên mở rộng bộ sưu tập. Nếu bạn cần thao tác dữ liệu với cấu trúc dữ liệu, danh sách có lẽ là cách thuận tiện hơn để sử dụng.
Đây là một trong những câu hỏi của trường lớp. Tập hợp T là một tập hợp trừu tượng; có thể có một triển khai mặc định (tôi không phải là .net / c # guy) nhưng một bộ sưu tập sẽ có các hoạt động cơ bản như thêm, xóa, lặp, v.v.
Danh sách của T ngụ ý một số chi tiết cụ thể về các hoạt động này: thêm nên mất thời gian liên tục, loại bỏ nên mất thời gian tỷ lệ với số phần tử, getfirst nên là thời gian phù hợp. Nói chung, Danh sách là một loại Tập hợp, nhưng Tập hợp không nhất thiết phải là một loại Danh sách.
Hanselman Speaks : " Collection<T>
trông giống như một danh sách và nó thậm chí có một danh sách List<T>
bên trong. MỌI phương pháp đơn lẻ ủy quyền cho nội bộ List<T>
. Nó bao gồm một thuộc tính được bảo vệ để lộ ra List<T>
."
EDIT: Collection<T>
không tồn tại trong System.Generic.Collections .NET 3.5. Nếu bạn di chuyển từ .NET 2.0 sang 3.5, bạn sẽ cần thay đổi một số mã nếu bạn đang sử dụng nhiềuCollection<T>
đối tượng, trừ khi tôi thiếu một số thứ rõ ràng ...
EDIT 2: Collection<T>
hiện nằm trong không gian tên System.Collections.ObjectModel trong .NET 3.5. Tệp trợ giúp cho biết điều này:
"Không gian tên System.Collections.ObjectModel chứa các lớp có thể được sử dụng làm bộ sưu tập trong mô hình đối tượng của một thư viện có thể sử dụng lại. Sử dụng các lớp này khi thuộc tính hoặc phương thức trả về bộ sưu tập."
Tất cả các giao diện này kế thừa từ IEnumerable
đó, bạn nên chắc chắn rằng mình hiểu. Về cơ bản, giao diện đó cho phép bạn sử dụng lớp trong một câu lệnh foreach (trong C #).
ICollection
là giao diện cơ bản nhất trong số các giao diện bạn đã liệt kê. Đó là một giao diện vô số hỗ trợ một Count
và đó là về nó.IList
là tất cả mọi thứ ICollection
, nhưng nó cũng hỗ trợ thêm và loại bỏ các mục, truy xuất các mục theo chỉ mục, v.v ... Đó là giao diện được sử dụng phổ biến nhất cho "danh sách các đối tượng", điều này rất mơ hồ mà tôi biết.IQueryable
là một giao diện có thể liệt kê hỗ trợ LINQ. Bạn luôn có thể tạo một IQueryable
từ IList và sử dụng LINQ tới Đối tượng, nhưng bạn cũng thấy IQueryable
được sử dụng để thực hiện hoãn lại các câu lệnh SQL trong LINQ tới SQL và LINQ tới Thực thể.IDictionary
là một động vật khác theo nghĩa nó là ánh xạ các khóa duy nhất đến các giá trị. Nó cũng có thể liệt kê ở chỗ bạn có thể liệt kê các cặp khóa / giá trị, nhưng nếu không thì nó phục vụ một mục đích khác với những cặp khác mà bạn đã liệt kêTheo MSDN, List (Of T) .Add là "một hoạt động O (n)" (khi "Dung lượng" bị vượt quá) trong khi Collection (Of T) .Add luôn là "một hoạt động O (1)". Điều đó có thể hiểu được nếu Danh sách được triển khai bằng Mảng và Tập hợp một Danh sách được Liên kết. Tuy nhiên, nếu đúng như vậy, người ta sẽ mong đợi Collection (Of T) .Item là "một hoạt động O (n)". Nhưng - nó - không phải !?! Collection (Of T) .Item là "một hoạt động O (1)" giống như List (Of T) .Item.
Trên hết, bài đăng "29/12/08 lúc 22:31" của "tuinstoel" ở trên tuyên bố kiểm tra tốc độ hiển thị Danh sách (Của T). Thêm để nhanh hơn Bộ sưu tập (Của T). Thêm mà tôi đã sao chép bằng Của Long và Chuỗi. Mặc dù tôi chỉ nhanh hơn ~ 33% so với tuyên bố của anh ấy là 80%, nhưng theo MSDN, nó đáng lẽ phải ngược lại và gấp "n" lần!?!
Cả hai đều triển khai các giao diện giống nhau, vì vậy chúng sẽ hoạt động theo cùng một cách. Có lẽ chúng được thực hiện khác nhau trong nội bộ, nhưng điều này sẽ phải được kiểm tra.
Sự khác biệt thực sự duy nhất tôi thấy là không gian tên và thực tế Collection<T>
được đánh dấu bằng ComVisibleAttribute(false)
, vì vậy mã COM không thể sử dụng nó.
Ngoài các asnwers khác, tôi đã biên soạn tổng quan nhanh về danh sách chung và khả năng thu thập. Bộ sưu tập là tập hợp con giới hạn của Danh sách:
* = hiện tại
o = hiện một phần
Bộ sưu tập Thuộc tính / Phương thức < T > Danh sách < 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() *