Tại sao nên sử dụng ICollection mà không phải là IEnumerable hoặc List <T> cho nhiều mối quan hệ nhiều-một / nhiều?


359

Tôi thấy điều này rất nhiều trong các hướng dẫn, với các thuộc tính điều hướng như ICollection<T>.

Đây có phải là một yêu cầu bắt buộc đối với Entity Framework không? Tôi có thể sử dụng IEnumerable?

Mục đích chính của việc sử dụng ICollectionthay vì IEnumerablehoặc thậm chí là List<T>gì?

Câu trả lời:


440

Thông thường những gì bạn chọn sẽ phụ thuộc vào phương pháp bạn cần truy cập. Nói chung - IEnumerable<>(MSDN: http://msdn.microsoft.com/en-us/l Library / system.collections.ienumerable.aspx ) cho một danh sách các đối tượng chỉ cần lặp đi lặp lại, ICollection<>(MSDN: http: // msdn.microsoft.com/en-us/l Library / 92t2ye13.aspx ) cho danh sách các đối tượng cần được lặp qua và sửa đổi, List<>để biết danh sách các đối tượng cần lặp đi lặp lại, sửa đổi, sắp xếp, v.v. (Xem tại đây để biết danh sách đầy đủ: http://msdn.microsoft.com/en-us/l Library / 6sh2ey19.aspx ).

Từ một quan điểm cụ thể hơn, lười tải đến để chơi với việc chọn loại. Theo mặc định, các thuộc tính điều hướng trong Entity Framework đi kèm với theo dõi thay đổi và là proxy. Để proxy động được tạo như một thuộc tính điều hướng, loại ảo phải thực hiện ICollection.

Thuộc tính điều hướng đại diện cho phần cuối "nhiều" của mối quan hệ phải trả về loại thực hiện ICollection, trong đó T là loại đối tượng ở đầu kia của mối quan hệ. - Yêu cầu để tạo proxy POCO MSDN

Thông tin thêm về Xác định và Quản lý Mối quan hệ MSDN


2
Vì vậy, với điều đó, Listsẽ tốt hơn rất nhiều, phải không?
Jan Carlo Viray

3
@JanCarloViray - Tôi có xu hướng sử dụng Listrất nhiều. Mặc dù nó có nhiều chi phí nhất nhưng nó cung cấp nhiều chức năng nhất.
Travis J

1
Danh sách được xác định nhiều hơn bởi các bộ chỉ mục của chúng hơn là khả năng sắp xếp chúng (có một bộ chỉ mục số nguyên giúp dễ dàng sắp xếp thứ gì đó, nhưng đó không phải là một yêu cầu).
phoog

2
Đối với chỉnh sửa của bạn, việc giới hạn một thuộc tính đối với loại giao diện không phải là về bộ nhớ mà là về đóng gói. Xem xét: private IEnumerable<int> _integers = new List<int> { 1, 2, 3 };sử dụng cùng bộ nhớ vớiprivate List<int> _integers = new List<int> { 1, 2, 3 };
phoog

13
@TravisJ: List<T>có một GetEnumerator()phương thức, tách biệt với cách triển khai của nó IEnumerable<T>, trả về một kiểu cấu trúc có thể thay đổi List<T>.Enumerator. Trong hầu hết các bối cảnh, loại đó sẽ mang lại hiệu suất tốt hơn một chút so với đối tượng heap độc lập. Trình biên dịch mà các liệt kê kiểu vịt (như cả C # và vb.net làm) có thể tận dụng lợi thế này khi tạo foreachmã. Nếu List<T>được truyền tới IEnumrable<T>trước foreach, IEnumerable<T>.GetEnumerator()phương thức sẽ trả về một đối tượng được phân bổ heap, không thể tối ưu hóa.
supercat

86

ICollection<T>được sử dụng vì IEnumerable<T>giao diện không cung cấp cách thêm mục, xóa mục hoặc sửa đổi bộ sưu tập.


3
Còn so sánh với Danh sách <T> thì sao?
Jan Carlo Viray

12
List<T>thực hiện ICollection<T>.
tiêu

Không chung chung ICollectionkhông cho phép bất kỳ cách nào để thêm các mục, nhưng nó vẫn là một công cụ bổ trợ hữu ích IEnumerable<T>vì nó cung cấp một Countthành viên thường nhanh hơn nhiều so với việc liệt kê mọi thứ. Lưu ý rằng nếu một IList<Cat>hoặc ICollection<Cat>được chuyển đến mã mong đợi IEnumerable<Animal>, Count()phương thức mở rộng sẽ nhanh nếu nó thực hiện không chung chung ICollection, nhưng không phải nếu nó chỉ thực hiện các giao diện chung vì thông thường ICollection<Cat>sẽ không thực hiện ICollection<Animal>.
supercat

58

Trả lời câu hỏi của bạn về List<T>:

List<T>là một lớp học; chỉ định một giao diện cho phép thực hiện linh hoạt hơn. Một câu hỏi tốt hơn là "tại sao không IList<T>?"

Để trả lời câu hỏi đó, hãy xem xét những gì IList<T>thêm vào ICollection<T>: lập chỉ mục số nguyên, có nghĩa là các mục có một số thứ tự tùy ý và có thể được truy xuất bằng cách tham chiếu đến thứ tự đó. Điều này có lẽ không có ý nghĩa trong hầu hết các trường hợp, vì các mặt hàng có thể cần phải được sắp xếp khác nhau trong các bối cảnh khác nhau.


21

Có một số khác biệt cơ bản giữa ICollection và IEnumerable

  • IEnumerable - chỉ chứa phương thức GetEnumerator để lấy Enumerator và cho phép lặp
  • ICollection chứa các phương thức bổ sung: Thêm, Xóa, Chứa, Đếm, Sao chép
  • ICollection được kế thừa từ IEnumerable
  • Với ICollection, bạn có thể sửa đổi bộ sưu tập bằng cách sử dụng các phương thức như thêm / xóa. Bạn không có quyền tự do làm điều tương tự với IEnumerable.

Chương trình đơn giản:

using System;
using System.Collections;
using System.Collections.Generic;

namespace StackDemo
{
    class Program 
    {
        static void Main(string[] args)
        {
            List<Person> persons = new List<Person>();
            persons.Add(new Person("John",30));
            persons.Add(new Person("Jack", 27));

            ICollection<Person> personCollection = persons;
            IEnumerable<Person> personEnumeration = persons;

            // IEnumeration
            // IEnumration Contains only GetEnumerator method to get Enumerator and make a looping
            foreach (Person p in personEnumeration)
            {                                   
               Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);
            }

            // ICollection
            // ICollection Add/Remove/Contains/Count/CopyTo
            // ICollection is inherited from IEnumerable
            personCollection.Add(new Person("Tim", 10));

            foreach (Person p in personCollection)
            {
                Console.WriteLine("Name:{0}, Age:{1}", p.Name, p.Age);        
            }
            Console.ReadLine();

        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age)
        {
            this.Name = name;
            this.Age = age;
        }
    }
}

13

Tôi nhớ nó theo cách này:

  1. IEnumerable có một phương thức GetEnumerator () cho phép một người đọc qua các giá trị trong một bộ sưu tập nhưng không ghi vào nó. Hầu hết sự phức tạp của việc sử dụng điều tra viên được chúng tôi quan tâm bởi mỗi câu lệnh trong C #. IEnumerable có một thuộc tính: Hiện tại, trả về phần tử hiện tại.

  2. ICollection triển khai IEnumerable và thêm một vài thuộc tính bổ sung mà phần lớn sử dụng là Count. Phiên bản chung của ICollection thực hiện các phương thức Add () và Remove ().

  3. IList thực hiện cả IEnumerable và ICollection, và thêm quyền truy cập lập chỉ mục số nguyên vào các mục (thường không bắt buộc, vì việc đặt hàng được thực hiện trong cơ sở dữ liệu).


4
Dựa trên những gì bạn đã viết ICollection và IList là như nhau. Vui lòng thêm những gì được thêm vào IList không tồn tại trong ICollection.
cược

ICollection VS IList, giao diện chỉ IList trong System.Collection chứa tất cả chức năng của IEnumerable và ICollection và chức năng bổ sung. IList có các phương thức Chèn và Xóa. Cả hai phương thức đều chấp nhận chỉ số trong tham số của chúng. Vì vậy, nó hỗ trợ các hoạt động dựa trên chỉ mục trên bộ sưu tập.
E.Meir

7

Ý tưởng cơ bản của việc sử dụng ICollectionlà cung cấp một giao diện để truy cập chỉ đọc một số lượng dữ liệu hữu hạn. Trong thực tế, bạn có một tài sản ICollection.Count . IEnumerablephù hợp hơn với một số chuỗi dữ liệu mà bạn đọc cho đến một số điểm logic, một số điều kiện được xác định rõ ràng bởi người tiêu dùng hoặc cho đến khi kết thúc liệt kê.


14
TIL rằng ICollection đọc trong khi ICollection<T>không.
Carl G

2

Các thuộc tính điều hướng thường được định nghĩa là ảo để chúng có thể tận dụng chức năng Entity Framework nhất định như tải lười biếng.

Nếu một thuộc tính điều hướng có thể chứa nhiều thực thể (như trong các mối quan hệ nhiều-nhiều hoặc một-nhiều), loại của nó phải là một danh sách trong đó các mục có thể được thêm, xóa và cập nhật, chẳng hạn như ICollection.

https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-USE-mvc/creating-an-entity-framework-data-model-for-an-asp-net- ứng dụng mvc


2

Những gì tôi đã làm trong là qua tuyên bố bộ sưu tập lớp bên trong của tôi sử dụng IList<Class>, ICollection<Class>hoặc IEnumerable<Class>(nếu danh sách tĩnh) tuỳ thuộc vào việc hay không tôi sẽ phải làm bất kỳ số lượng các nội dung sau trong một phương pháp trong kho của tôi: enumerate, sắp xếp / đặt hàng hoặc sửa đổi . Khi tôi chỉ cần liệt kê (và có thể sắp xếp) trên các đối tượng thì tôi tạo một temp List<Class>để làm việc với bộ sưu tập trong một phương thức IEnumerable. Tôi nghĩ rằng thực tế này sẽ chỉ có hiệu quả nếu bộ sưu tập tương đối nhỏ, nhưng nó có thể là thực hành tốt nói chung, idk. Xin vui lòng sửa cho tôi nếu có bằng chứng là tại sao điều này sẽ không thực hành tốt.


0

Hãy thử suy nghĩ bên ngoài hộp với / bằng logic và hiểu rõ ba giao diện này trong câu hỏi của bạn:

Khi lớp của một số thể hiện thực hiện giao diện System.Collection.IEnumerable, nói một cách đơn giản, chúng ta có thể nói rằng cá thể này có thể đếm được và lặp lại được, điều đó có nghĩa là cá thể này cho phép bằng cách nào đó trong một vòng lặp đi / get / pass / traverse / lặp đi lặp lại / thông qua tất cả các mục và thành phần mà thể hiện này chứa.

Điều này có nghĩa là điều này cũng có thể liệt kê tất cả các mục và thành phần mà thể hiện này chứa.

Mỗi lớp thực hiện giao diện System.Collection.IEnumerable cũng thực hiện phương thức GetEnumerator không có đối số và trả về một thể hiện System.Collections.IEnumerator.

Giao diện của System.Collections.IEnumerator hoạt động rất giống với các trình lặp C ++.

Khi lớp của một số thể hiện thực hiện giao diện System.Collection.ICollection, nói một cách đơn giản, chúng ta có thể nói rằng thể hiện này là một số tập hợp các thứ.

Phiên bản chung của giao diện này, tức là System.Collection.Generic.ICollection, có nhiều thông tin hơn vì giao diện chung này nêu rõ loại hình của những thứ trong bộ sưu tập.

Đây là tất cả hợp lý, hợp lý, hợp lý và hợp lý khi giao diện System.Collections.ICollection thừa hưởng từ giao diện System.Collections.IEnumerable, bởi vì về mặt lý thuyết, mọi bộ sưu tập cũng có thể đếm được và lặp lại và về mặt lý thuyết là có thể vượt qua tất cả các mục và phần tử trong mọi bộ sưu tập.

Giao diện System.Collections.ICollection đại diện cho một bộ sưu tập động hữu hạn có thể thay đổi, có nghĩa là các mục tồn tại có thể được xóa khỏi bộ sưu tập và các mục mới có thể được thêm vào cùng một bộ sưu tập.

Điều này giải thích tại sao giao diện System.Collections.ICollection có các phương thức "Thêm" và "Xóa".

Bởi vì các phiên bản của giao diện System.Collections.ICollection là các bộ sưu tập hữu hạn nên từ "hữu hạn" ngụ ý rằng mọi bộ sưu tập của giao diện này luôn có số lượng mục và phần tử hữu hạn trong đó.

Giao diện Count of System.Collections.ICollection có thể trả về số này.

Giao diện System.Collections.IEnumerable không có các phương thức và thuộc tính này mà giao diện System.Collections.ICollection có, bởi vì nó không có ý nghĩa gì khi System.Collections.IEnumerable sẽ có các phương thức và thuộc tính này mà giao diện System.Collections.ICollection có.

Logic cũng nói rằng mọi trường hợp cả vô số và lặp lại không nhất thiết phải là một bộ sưu tập và không nhất thiết phải thay đổi.

Khi tôi nói có thể thay đổi, tôi có nghĩa là đừng nghĩ ngay rằng bạn có thể thêm hoặc xóa thứ gì đó khỏi thứ gì đó có thể đếm được và lặp lại được.

Ví dụ, nếu tôi chỉ tạo một số số nguyên tố hữu hạn, thì số thứ tự hữu hạn này thực sự là một thể hiện của giao diện System.Collections.IEnumerable, bởi vì bây giờ tôi có thể đi qua tất cả các số nguyên tố trong chuỗi hữu hạn này trong một vòng lặp và làm bất cứ điều gì tôi muốn làm với từng người trong số họ, như in từng người trong số họ ra cửa sổ hoặc màn hình điều khiển, nhưng chuỗi số nguyên tố hữu hạn này không phải là một phiên bản của giao diện System.Collections.ICollection, vì điều này không có ý nghĩa gì với thêm số tổng hợp vào dãy số hữu hạn này.

Ngoài ra, bạn muốn trong lần lặp tiếp theo để có được số nguyên tố lớn nhất gần nhất tiếp theo với số nguyên tố hiện tại trong lần lặp hiện tại, nếu vậy bạn cũng không muốn xóa các số nguyên tố tồn tại khỏi dãy số nguyên tố hữu hạn này.

Ngoài ra, bạn có thể muốn sử dụng, viết mã và viết "lợi nhuận" trong phương thức GetEnumerator của giao diện System.Collections.IEnumerable để tạo ra các số nguyên tố và không phân bổ bất cứ thứ gì trên đống bộ nhớ và sau đó giao nhiệm vụ cho Garbage Collector (GC) cho cả hai giải phóng và giải phóng bộ nhớ này khỏi heap, vì điều này rõ ràng vừa lãng phí bộ nhớ hệ điều hành vừa làm giảm hiệu năng.

Việc phân bổ và giải quyết bộ nhớ động trên heap nên được thực hiện khi gọi các phương thức và thuộc tính của giao diện System.Collections.ICollection, nhưng không phải khi gọi các phương thức và thuộc tính của giao diện System.Collections.IEnumerable (mặc dù giao diện System.Collections.IEnumerable chỉ có 1 phương thức và 0 thuộc tính).

Theo những gì người khác nói trong trang web Stack Overflow này, giao diện đơn giản System.Collections.IList đại diện cho một orderable bộ sưu tập có và điều này giải thích tại sao các phương thức của giao diện System.Collections.IList hoạt động với các chỉ mục trái ngược với các giao diện System.Collections.ICollection.

Trong giao diện System.Collections.ICollection ngắn không ngụ ý rằng một phiên bản của nó có thể được sắp xếp theo thứ tự, nhưng giao diện System.Collections.IList không ngụ ý điều đó.

Bộ theo thứ tự lý thuyết là trường hợp đặc biệt của bộ không có thứ tự.

Điều này cũng có ý nghĩa và giải thích tại sao giao diện System.Collections.IList thừa hưởng giao diện System.Collections.ICollection.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.