Tại sao mảng thực hiện IList?


141

Xem định nghĩa của lớp System.Array

public abstract class Array : IList, ...

Về mặt lý thuyết, tôi sẽ có thể viết bit này và hạnh phúc

int[] list = new int[] {};
IList iList = (IList)list;

Tôi cũng có thể gọi bất kỳ phương thức nào từ iList

 ilist.Add(1); //exception here

Câu hỏi của tôi không phải là tại sao tôi nhận được một ngoại lệ, mà là tại sao Array thực hiện IList ?


22
Tốt câu hỏi. Tôi không bao giờ thích ý tưởng về giao diện chất béo (đó là thuật ngữ kỹ thuật cho kiểu thiết kế này).
Konrad Rudolph


2
Có ai thực sự quan tâm đến LSP? Nó có vẻ khá hàn lâm với tôi.
Gabe

13
@Gabe, sau đó bạn cần phải làm việc với các cơ sở mã lớn hơn. Thực hiện một hành vi (kế thừa từ một giao diện) và sau đó chỉ cần bỏ qua những thứ bạn không thích / không thể hỗ trợ dẫn đến mùi hôi, bị che khuất, đúc và cuối cùng: mã lỗi.
Marius

3
@Gabe là bộ sưu tập ngụ ý khả năng biến đổi không phải là các thực thể chứa trong nó. Bạn có thể biến thành viên lớp của mình thành một loại thực hiện cả IRWList <> và IReadList <>, sử dụng nếu như IRWList <> bên trong lớp của bạn và hiển thị nó dưới dạng IReadList. Có, bạn phải đặt sự phức tạp ở đâu đó, nhưng tôi không thấy điều đó áp dụng cho việc coi thường LSP như một nguyên tắc thiết kế rất tốt (không biết về tài sản IsReadOnly mặc dù điều này khiến IList phức tạp hơn từ quan điểm của người tiêu dùng)
Marius

Câu trả lời:


94

Bởi vì một mảng cho phép truy cập nhanh theo chỉ mục và IList/ IList<T>là các giao diện bộ sưu tập duy nhất hỗ trợ điều này. Vì vậy, có lẽ câu hỏi thực sự của bạn là "Tại sao không có giao diện cho các bộ sưu tập liên tục với các bộ chỉ mục?" Và tôi không có câu trả lời.

Không có giao diện chỉ đọc cho các bộ sưu tập. Và tôi đang thiếu những thứ thậm chí nhiều hơn một kích thước không đổi với giao diện bộ chỉ mục.

IMO cần có thêm một số giao diện bộ sưu tập (chung) tùy thuộc vào các tính năng của bộ sưu tập. Và những cái tên cũng nên khác đi, Listvì một cái gì đó với một người lập chỉ mục là IMO thực sự ngu ngốc.

  • Chỉ cần liệt kê IEnumerable<T>
  • Chỉ đọc nhưng không có chỉ mục (.Count, .Contains, ...)
  • Có thể thay đổi kích thước nhưng không có bộ chỉ mục, tức là đặt như (Thêm, Xóa, ...) hiện tại ICollection<T>
  • Chỉ đọc với bộ chỉ mục (bộ chỉ mục, bộ chỉ mục, ...)
  • Kích thước không đổi với bộ chỉ mục (bộ chỉ mục với bộ cài đặt)
  • Kích thước thay đổi với bộ chỉ mục (Chèn, ...) hiện tại IList<T>

Tôi nghĩ rằng các giao diện bộ sưu tập hiện tại là thiết kế xấu. Nhưng vì chúng có các thuộc tính cho bạn biết phương thức nào là hợp lệ (và đây là một phần trong hợp đồng của các phương thức này) nên nó không phá vỡ nguyên tắc thay thế.


14
cảm ơn câu trả lời Nhưng tôi thay vì để lại câu hỏi như vậy. Lý do rất đơn giản. Giao diện là một hợp đồng công cộng. Nếu một người thực hiện nó, người ta phải thực hiện đầy đủ tất cả các thành viên, nếu không nó phá vỡ LSP và thường có mùi khó chịu, phải không?
oleksii

16
Nó phá vỡ LSP. Nếu nó không liệt kê. Thêm (mục) nên thêm mục vào danh sách bất kể loại cụ thể. Trừ những trường hợp ngoại lệ. Trong triển khai mảng, ném một ngoại lệ trong trường hợp không ngoại lệ, trong đó tự nó là thực tiễn xấu
Rune FS

2
@smelch Tôi xin lỗi nhưng bạn đã nhầm LSP rồi. Một mảng không thực hiện addvà do đó không thể được thay thế cho một cái gì đó khi khả năng đó được yêu cầu.
Rune FS

7
Tôi thừa nhận rằng về mặt kỹ thuật nó không vi phạm LSP chỉ vì tài liệu nói rằng bạn nên kiểm tra IsFixedSizeIsReadOnlycác thuộc tính, nó chắc chắn vi phạm nguyên tắc Nói, Đừng hỏiNguyên tắc ít gây bất ngờ nhất . Tại sao phải triển khai giao diện khi bạn sẽ ném ngoại lệ cho 4 trong số 9 phương thức?
Matthew

11
Một thời gian đã trôi qua kể từ câu hỏi ban đầu. Nhưng bây giờ với .Net 4.5, có thêm giao diện IReadOnlyListIReadOnlyCollection .
Tobias

43

Phần nhận xét của tài liệu cho IListbiết

IList là hậu duệ của giao diện ICollection và là giao diện cơ sở của tất cả các danh sách không chung chung. Việc triển khai IList rơi vào ba loại: chỉ đọc, kích thước cố định và kích thước biến . Một IList chỉ đọc không thể được sửa đổi. IList có kích thước cố định không cho phép thêm hoặc loại bỏ các phần tử, nhưng nó cho phép sửa đổi các phần tử hiện có. Một IList có kích thước thay đổi cho phép bổ sung, loại bỏ và sửa đổi các yếu tố.

Rõ ràng các mảng rơi vào loại kích thước cố định, do đó, sự sai lệch của giao diện, nó có ý nghĩa.


4
Tôi đoán họ đã kết thúc với rất nhiều giao diện. IListFixedSize, IListReadOnly ...
Magnus

9
đó thực sự là một câu trả lời tốt từ quan điểm của tài liệu. Nhưng với tôi nó trông giống như một bản hack. Các giao diện phải mỏng và đơn giản để một lớp thực hiện tất cả các thành viên.
oleksii

1
@oleksii: Tôi đồng ý. Giao diện và ngoại lệ thời gian chạy không phải là sự kết hợp thanh lịch nhất. Để bảo vệ Arraynó thực hiện Addphương pháp một cách rõ ràng, làm giảm nguy cơ gọi nó một cách tình cờ.
Brian Rasmussen

Cho đến khi chúng tôi tạo ra một triển khai IListkhông cho phép cả sửa đổi bổ sung / xóa. Sau đó, các tài liệu không còn chính xác. : P
Timo

1
@Magnus - Trong .Net 4.5, có thêm giao diện IReadOnlyListIReadOnlyCollection .
RBT

17

Bởi vì không phải tất cả các ILists đều có thể thay đổi (xem IList.IsFixedSizeIList.IsReadOnly) và các mảng chắc chắn hoạt động giống như các danh sách có kích thước cố định.

Nếu câu hỏi của bạn thực sự là "tại sao nó thực hiện một giao diện không chung chung ", thì câu trả lời là những thứ này xuất hiện trước khi thuốc generic xuất hiện.


10
@oleksii: Không, nó không phá vỡ LSP, vì IList chính giao diện cho bạn biết rằng nó có thể không thể thay đổi. Nếu trên thực tế nó được đảm bảo là có thể thay đổi và mảng nói với bạn nếu không, thì nó sẽ phá vỡ quy tắc.
dùng541686

Trên thực tế, Array không phá vỡ LSP trong trường hợp chung IList<T>và không phá vỡ nó trong trường hợp không chung chung IList: enterpriseccraft
Skill.com/2014/11/22/iêu

5

Đó là một di sản mà chúng ta có từ thời chưa rõ cách xử lý các bộ sưu tập chỉ đọc và liệu Array có được đọc hay không. Có các cờ IsFixedSize và IsReadOnly trong giao diện IList. Cờ IsReadOnly có nghĩa là bộ sưu tập hoàn toàn không thể thay đổi và IsFixedSize có nghĩa là bộ sưu tập không cho phép sửa đổi, nhưng không thêm hoặc xóa các mục.

Tại thời điểm .Net 4.5, rõ ràng một số giao diện "trung gian" được yêu cầu để hoạt động với các bộ sưu tập chỉ đọc, do đó IReadOnlyCollection<T>IReadOnlyList<T>đã được giới thiệu.

Đây là một bài đăng blog tuyệt vời mô tả chi tiết: Chỉ đọc các bộ sưu tập trong .NET


0

Định nghĩa giao diện IList là "Đại diện cho một bộ sưu tập các đối tượng không chung chung có thể được truy cập riêng lẻ theo chỉ mục." Mảng hoàn toàn thỏa mãn định nghĩa này, vì vậy phải thực hiện giao diện. Ngoại lệ khi gọi phương thức Add () là "System.NotSupportedException: Collection có kích thước cố định" và xảy ra do mảng không thể tăng khả năng của nó một cách linh hoạt. Khả năng của nó được xác định trong quá trình tạo đối tượng mảng.


0

Việc một mảng triển khai IList (và liên tục, ICollection) đã đơn giản hóa công cụ Linq2Objects, vì việc chuyển IEnumerable sang IList / ICollection cũng sẽ hoạt động cho các mảng.

Ví dụ, Count () kết thúc bằng cách gọi Array.Lipse under-the-hood, vì nó được truyền tới ICollection và việc triển khai của mảng trả về Độ dài.

Nếu không có điều này, công cụ Linq2Objects sẽ không có cách xử lý đặc biệt cho mảng và thực hiện khủng khiếp, hoặc họ cần phải tăng gấp đôi mã thêm xử lý trường hợp đặc biệt cho mảng (như họ làm cho IList). Thay vào đó, họ phải chọn thực hiện mảng IList.

Đó là sự đảm nhận của tôi về "Tại sao".


0

Ngoài ra chi tiết triển khai LINQ Kiểm tra lần cuối cho IList, nếu nó không thực hiện danh sách, họ sẽ cần 2 kiểm tra làm chậm tất cả các cuộc gọi cuối hoặc có Last trên một mảng lấy O (N)

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.