2009-12-09 28 views
12

Khi chúng ta khai báo một tham số như ICollection và khởi tạo đối tượng là List, tại sao chúng ta không thể lấy lại các chỉ mục? ví dụ:Tại sao chỉ mục ICollection không hoạt động khi được khởi tạo?

ICollection<ProductDTO> Products = new List<ProductDTO>(); 
Products.Add(new ProductDTO(1,"Pen")); 
Products.Add(new ProductDTO(2,"Notebook"));

Sau đó, điều này sẽ không làm việc:

ProductDTO product = (ProductDTO)Products[0];

gì là chút tôi đang thiếu?
[Có, chúng tôi có thể sử dụng Danh sách như tuyên bố một nó có thể làm việc, nhưng tôi không muốn khai báo dạng danh sách, như:

List<ProductDTO> Products = new List<ProductDTO>();

]

+0

Bạn có nghĩa là 'Sản phẩm .Thêm (ProductDTO mới (1, "Bút")); '? –

+0

Đây có phải là ví dụ thực tế không? Cả List và ICollection đều không có quá tải cho phương thức Add có hai đối số? –

Trả lời

20

Giao diện ICollection không tuyên bố một indexer, vì vậy bạn không thể sử dụng lập chỉ mục để lấy phần tử thông qua một tài liệu tham khảo của loại đó.

Bạn có thể thử IList, điều này bổ sung thêm một số chức năng khác, trong khi vẫn đang bị trừu tượng. Tất nhiên, điều này có thể ảnh hưởng đến các quyết định thiết kế khác vì vậy tôi sẽ xem xét kỹ điều này.

+0

Khi bạn nói quyết định thiết kế. Ý anh là gì? Điều gì là tốt nhất khi sử dụng IList hoặc ICollection? –

+1

@Inanikian Không có "tốt nhất"; nó phụ thuộc vào ngữ cảnh. Nếu bạn phải sử dụng các phương thức trong IList , giả sử nếu bạn yêu cầu lập chỉ mục/sắp xếp, thì IList có thể là loại giao diện tốt nhất để yêu cầu. Mặt khác, nếu bạn chỉ quan tâm đếm, thêm, xóa và liệt kê các mục, nhưng không bao giờ theo chỉ mục và không muốn áp đặt yêu cầu chức năng bổ sung trên lớp để có trình chỉ mục và tất cả các chức năng khác ngụ ý bởi IList rằng bạn sẽ không sử dụng anyway, sau đó nó có thể tốt hơn để yêu cầu chỉ những gì bạn cần, ví dụ, ICollection (hoặc thậm chí IEnumerable , nếu bạn không sửa đổi bất cứ điều gì). –

7

ICollection không định nghĩa một indexer.

ICollection Non-Generic

ICollection Generic

+0

Liên kết của bạn là ICollection không chung chung, bạn nên bổ sung nó vào biểu mẫu chung @ http://msdn.microsoft.com/en-us/library/92t2ye13.aspx – jball

+0

@BasicallyMoney Đôi khi câu trả lời ngắn là tất cả những gì cần thiết. – jball

+1

Câu trả lời xác thực nhanh hơn để đọc.Và người dùng không thích đọc, nhớ không? :) –

4

Vấn đề cơ bản là ICollection không xác định chỉ mục. Đối với Danh sách này được thực hiện bằng cách thực hiện IList.

Hãy thử điều này:

IList<ProductDTO> Products = new List<ProductDTO>(); 

Alternatly, bạn có thể tiếp tục sử dụng ICollection và chuyển đổi sang một mảng khi bạn cần truy cập vào những thành tố của chỉ số:

ICollection<ProductDTO> Products = new List<ProductDTO>();   
ProductDTO z = Products.ToArray()[0]; 
+0

'ICollection <>' không có phương thức ToArray trên nó - đó là 'List <>'. Thay vào đó, bạn cần 'CopyTo'. – thecoop

+5

Phụ thuộc vào phiên bản .net. ToArray() là một phương thức mở rộng từ khung công tác 3.x .net. –

2

Sau đó, điều này sẽ làm việc:

ProductDTO product = ((IList<ProductDTO>)Products)[0]; 

Lý do là trình biên dịch đánh giá lvalue, đó là biến ở bên trái của '=', để tìm ra phương pháp và thuộc tính nào, nó biết nó có thể truy cập tại thời gian biên dịch. Điều này được gọi là gõ tĩnh, và đảm bảo rằng một thành viên đối tượng có thể được truy cập trực tiếp tại thời gian chạy bằng cách biết rằng thành viên luôn có thể truy cập được.

+1

Điều này giúp loại bỏ lợi ích khi làm việc với sự trừu tượng được cung cấp bởi giao diện: nếu Sản phẩm sau đó được thay đổi thành một cái gì đó khác với Danh sách , đoạn mã trên bị hỏng vì nó giả định về kiểu cơ bản khi thực hiện dàn diễn viên. –

+0

Có, nhưng nó sửa chữa một tuyên bố duy nhất mà OP phàn nàn. –

+2

Bạn và tôi có các định nghĩa khác nhau của từ ** sửa **! ;-) –

17

Sử dụng LINQ, bạn có thể làm điều này:

ProductDTO product = (ProductDTO)Products.ElementAt(0); 
1

Sử dụng LINQ, bạn có thể truy cập vào một phần tử trong một ICollection <> ở một chỉ số cụ thể như thế này:

myICollection.AsEnumerable().ElementAt(myIndex); 
Các vấn đề liên quan