Không thể chuyển đổi từ IEnumerable <T> sang ICollection <T>


91

Tôi đã xác định những điều sau:

public ICollection<Item> Items { get; set; }

Khi tôi chạy mã này:

Items = _item.Get("001");

Tôi nhận được thông báo sau:

Error   3   
Cannot implicitly convert type 
'System.Collections.Generic.IEnumerable<Storage.Models.Item>' to 
'System.Collections.Generic.ICollection<Storage.Models.Item>'. 
An explicit conversion exists (are you missing a cast?)

Ai đó có thể giải thích những gì tôi đang làm sai. Tôi rất bối rối về sự khác biệt giữa Enumerable, Collections và sử dụng ToList ()

Đã thêm thông tin

Sau đó trong mã của tôi, tôi có những thứ sau:

for (var index = 0; index < Items.Count(); index++) 

Tôi có ổn không khi định nghĩa các Mục dưới dạng IEnumerable?


3
Bạn có thể cung cấp thêm thông tin về loại _item và chữ ký của Get (string) (cụ thể là kiểu trả về) không?
— Tiến sĩ Andrew Burnett-Thompson

Tại sao không thay đổi kiểu như thế này? public IEnumerable<Item> Items { get; set; }Bạn có lý do đặc biệt nào để có nó như ICollectionvậy không?
— Shadow Wizard là Ear For You

IEnumerable <T> Get (chuỗi pk);
— Samantha JT Star

Câu trả lời:


113

ICollection<T>kế thừa từ IEnumerable<T>đó để gán kết quả của

IEnumerable<T> Get(string pk)

một ICollection<T>có hai cách.

// 1. You know that the referenced object implements `ICollection<T>`,
//    so you can use a cast
ICollection<T> c = (ICollection<T>)Get("pk");

// 2. The returned object can be any `IEnumerable<T>`, so you need to 
//    enumerate it and put it into something implementing `ICollection<T>`. 
//    The easiest is to use `ToList()`:
ICollection<T> c = Get("pk").ToList();

Các tùy chọn thứ hai linh hoạt hơn, nhưng có tác động hiệu suất lớn hơn nhiều. Một tùy chọn khác là lưu trữ kết quả IEnumerable<T>trừ khi bạn cần thêm chức năng bổ sung của ICollection<T>giao diện.

Nhận xét bổ sung về hiệu suất

Vòng lặp bạn có

for (var index = 0; index < Items.Count(); index++)

hoạt động trên một IEnumerable<T>nhưng nó không hiệu quả; mỗi lệnh gọi Count()yêu cầu một bảng liệt kê đầy đủ tất cả các phần tử. Sử dụng một tập hợp và thuộc Counttính (không có dấu ngoặc đơn) hoặc chuyển đổi nó thành một vòng lặp foreach:

foreach(var item in Items)

1
Chức năng bổ sung được bổ sung bởi ICollection là gì?
— Samantha JT Star

7
ICollection<T>có thể được thao tác (xem tài liệu để biết chi tiết), trong khi một IEnumerable<T>chỉ có thể được liệt kê.
— Anders Abel

Tôi cần có thứ gì đó để có thể chạy các truy vấn LINQ khác nhau. Tôi không cần thêm hoặc làm bất cứ điều gì tương tự vào danh sách. Điều đó có nghĩa là tôi sẽ tốt hơn với ICollection.
— Samantha JT Star

LINQ hoạt động IEnumerable<T>như vậy IEnumerable<T>là đủ trong trường hợp đó.
— Anders Abel

31

Bạn không thể chuyển đổi trực tiếp từ IEnumerable<T>sang ICollection<T>. Bạn có thể sử dụng ToListphương thức của IEnumerable<T>để chuyển đổi nó thànhICollection<T>

someICollection = SomeIEnumerable.ToList();


Điều này làm việc cho tôi. Nhưng tôi có nên chuyển đổi không hay tốt hơn là tôi nên sử dụng IEnumerable làm loại cho các Mục. Nếu tôi sử dụng IEnumerable, tôi có đang tạo nó để tôi có thể thực hiện nhiều thao tác hơn trên các Mục nếu cần sau này trong chương trình của tôi không?
— Samantha JT Star

ICollection đã triển khai IEnumerable. Nếu bạn lo lắng về các hành động có sẵn, tôi nghĩ bạn nên đi ICollection. Sẽ tốt hơn nếu bạn có thể đọc phần chênh lệch thực tế giữa hai và sau đó quyết định những gì thực sự bạn muốn sử dụng
— Haris Hasan

Tôi đang cố gắng hiểu những lợi ích mà tôi sẽ có nếu tôi sử dụng ToList (). Sau khi có dữ liệu, tôi muốn chạy các truy vấn LINQ đối với các Mục.
— Samantha JT Star

ToList () sẽ hoạt động nhưng như bạn đã nêu trong nhận xét của mình Get () trả về ICollection, vì vậy thực sự bạn chỉ cần thực hiện ép kiểu sang ICollection <T>, hoặc tốt hơn là thay đổi chữ ký trả về của Get to ICollection <T> . Sử dụng ToList hoặc ToArray sẽ làm việc, nhưng nó cũng sẽ phải chịu một tạo bộ nhớ không cần thiết / bản sao hoạt động
— Tiến sĩ Andrew Burnett-Thompson

Bạn có thể chạy các truy vấn LINQ dựa trên IEnumerable và ICollection. Ưu điểm .. một điều tôi biết ngay bây giờ là Bộ sưu tập đếm duy trì số lượng và kết quả trả về IEnumerable bằng cách tính toán nó có bao nhiêu mục. ICollection cung cấp phương pháp loại bỏ bổ sung mà IEnumerables không
— Haris Hasan

1

Đang chờ thêm thông tin về câu hỏi:

vui lòng cung cấp thêm thông tin về loại mặt hàng và chữ ký của Nhận

Hai điều bạn có thể thử là:

  • Để truyền giá trị trả về của _item.Get tới (ICollection)
  • thứ hai là sử dụng _item.Get ("001"). ToArray () hoặc _item.Get ("001"). ToList ()

Xin lưu ý rằng thứ hai sẽ phải chịu một lần truy cập hiệu suất cho bản sao mảng. Nếu chữ ký (kiểu trả về) của Get không phải là ICollection thì chữ ký đầu tiên sẽ không hoạt động, nếu nó không phải là IEnumerable thì chữ ký thứ hai sẽ không hoạt động.


Sau khi bạn làm rõ câu hỏi và trong nhận xét, cá nhân tôi sẽ khai báo kiểu trả về _item.Get ("001") cho ICollection. Điều này có nghĩa là bạn sẽ không phải thực hiện bất kỳ quá trình truyền hoặc chuyển đổi nào (thông qua ToList / ToArray) sẽ liên quan đến hoạt động tạo / sao chép không cần thiết.

// Leave this the same
public ICollection<Item> Items { get; set; }

// Change function signature here:
// As you mention Item uses the same underlying type, just return an ICollection<T>
public ICollection<Item> Get(string value); 

// Ideally here you want to call .Count on the collectoin, not .Count() on 
// IEnumerable, as this will result in a new Enumerator being created 
// per loop iteration
for (var index = 0; index < Items.Count(); index++) 

Trân trọng,


1
Chữ ký là: IEnumerable <T> Get (string pk); Các mục được sử dụng để giữ các bản ghi Mục được trả lại. Sau đó, tôi lặp lại những điều này để tạo báo cáo. Tôi sẽ ổn nếu sử dụng bất cứ thứ gì có hiệu quả. Bạn nghĩ loại dữ liệu tốt nhất sẽ là gì?
— Samantha JT Star

1
Tôi khuyên bạn nên thay đổi kiểu dữ liệu của Mục thành IEnumerable <T> để khớp với Nhận hoặc thay đổi kiểu trả về của Nhận thành ICollection <T> để khớp với Mục. Tôi giả sử hai điều này là cùng một loại cơ bản chỉ được khai báo khác nhau? NẾU chúng là cùng kiểu bạn muốn tránh sử dụng ToList () hoặc ToArray () vì điều đó thực hiện cấp phát bộ nhớ và sao chép mảng không cần thiết. Nếu họ không cùng loại, bạn phải làm một số chuyển đổi
— Tiến sĩ Andrew Burnett-Thompson

Tôi đã thêm vào câu hỏi để hiển thị vị trí sau này tôi sử dụng các Mục. Bạn đã đúng khi nói cùng một loại cơ bản.
— Samantha JT Star

Ok, sau đó tôi sẽ chỉ thay đổi kiểu trả về của Get, vì sau đó bạn không cần thực hiện bất kỳ chuyển đổi nào (thông qua ToList / ToArray, chậm) hoặc truyền. Hy vọng điều này sẽ giúp :)
— Tiến sĩ Andrew Burnett-Thompson
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 cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.