Tidak dapat mengubah dari IEnumerable <T> menjadi ICollection <T>

91

Saya telah mendefinisikan yang berikut ini:

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

Ketika saya menjalankan kode ini:

Items = _item.Get("001");

Saya mendapatkan pesan berikut:

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?)

Adakah yang bisa menjelaskan kesalahan saya. Saya sangat bingung tentang perbedaan antara Enumerable, Collections dan menggunakan ToList ()

Informasi tambahan

Nanti di kode saya, saya memiliki yang berikut:

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

Apakah saya boleh mendefinisikan Item sebagai IEnumerable?

Samantha JT Star
sumber
3
Dapatkah Anda memberikan informasi lebih lanjut tentang tipe _item dan tanda tangan Get (string) (khusus tipe kembalian)?
Dr. Andrew Burnett-Thompson
Mengapa tidak mengubah tipe seperti ini? public IEnumerable<Item> Items { get; set; }Apakah Anda punya alasan khusus untuk memilikinya ICollection?
Shadow Wizard adalah Ear For You
IEnumerable <T> Get (string pk);
Samantha JT Star

Jawaban:

113

ICollection<T>mewarisi dari IEnumerable<T>sehingga untuk menetapkan hasil

IEnumerable<T> Get(string pk)

ke ICollection<T>ada dua cara.

// 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();

Opsi kedua lebih fleksibel, tetapi memiliki dampak kinerja yang jauh lebih besar. Pilihan lainnya adalah menyimpan hasil sebagai IEnumerable<T>kecuali Anda memerlukan fungsionalitas tambahan yang ditambahkan oleh ICollection<T>antarmuka.

Komentar Kinerja Tambahan

Lingkaran yang Anda miliki

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

bekerja pada suatu IEnumerable<T>tetapi tidak efisien; setiap panggilan ke Count()membutuhkan penghitungan lengkap semua elemen. Gunakan koleksi dan Countproperti (tanpa tanda kurung) atau ubah menjadi foreach loop:

foreach(var item in Items)
Anders Abel
sumber
1
Apa fungsi tambahan yang ditambahkan oleh ICollection?
Samantha JT Star
7
ICollection<T>dapat dimanipulasi (lihat dokumen untuk detailnya), sedangkan an IEnumerable<T>hanya dapat disebutkan.
Anders Abel
Saya perlu memiliki sesuatu di mana saya dapat menjalankan kueri LINQ yang berbeda. Saya tidak perlu menambahkan atau melakukan hal seperti itu ke dalam daftar. Apakah itu berarti saya akan lebih baik dengan ICollection.
Samantha JT Star
LINQ bekerja IEnumerable<T>begitu IEnumerable<T>saja dalam kasus itu.
Anders Abel
31

Anda tidak dapat mengonversi langsung dari IEnumerable<T>ke ICollection<T>. Anda dapat menggunakan ToListmetode IEnumerable<T>untuk mengubahnya menjadiICollection<T>

someICollection = SomeIEnumerable.ToList();

Haris Hasan
sumber
Ini berhasil untuk saya. Tetapi apakah ide yang baik bagi saya untuk mengonversi atau apakah saya lebih baik menggunakan IEnumerable sebagai tipe untuk Item. Jika saya menggunakan IEnumerable, apakah saya membuatnya sehingga saya dapat melakukan lebih banyak tindakan pada Item jika diperlukan nanti dalam program saya?
Samantha JT Star
ICollection sudah mengimplementasikan IEnumerable. Jika Anda khawatir tentang tindakan yang tersedia, saya pikir Anda harus menggunakan ICollection. Lebih baik jika Anda dapat membaca perbedaan sebenarnya antara keduanya dan kemudian memutuskan apa yang sebenarnya ingin Anda gunakan
Haris Hasan
Saya mencoba untuk memahami keuntungan apa yang akan saya dapatkan jika saya menggunakan ToList (). Setelah saya memiliki data, saya ingin menjalankan kueri LINQ terhadap Item.
Samantha JT Star
ToList () akan berfungsi tetapi seperti yang Anda nyatakan dalam komentar Anda Get () mengembalikan sebuah ICollection, jadi sebenarnya Anda hanya perlu melakukan cast ke ICollection <T>, atau lebih baik lagi, ubah tanda tangan kembali Get to ICollection <T> . Menggunakan ToList atau ToArray akan berfungsi, tetapi juga akan menimbulkan operasi pembuatan memori / salin yang tidak perlu
Dr. Andrew Burnett-Thompson
Anda dapat menjalankan kueri LINQ terhadap IEnumerable dan ICollection. Keuntungan .. yang saya tahu sekarang adalah Count ICollection mempertahankan hitungan dan hasil pengembalian IEnumerable dengan menghitung berapa banyak item yang dimilikinya. ICollection menyediakan metode penghapusan tambahan yang tidak dimiliki Ienumerables
Haris Hasan
1

Menunggu informasi lebih lanjut tentang pertanyaan:

berikan informasi lebih lanjut tentang jenis barang dan tanda tangan Get

Dua hal yang bisa Anda coba adalah:

  • Untuk mentransmisikan nilai kembali dari _item. Dapatkan ke (ICollection)
  • kedua menggunakan _item.Get ("001"). ToArray () atau _item.Get ("001"). ToList ()

Harap dicatat yang kedua akan menimbulkan kinerja hit untuk salinan array. Jika tanda tangan (tipe pengembalian) dari Get bukan ICollection maka yang pertama tidak akan berfungsi, jika bukan IEnumerable maka yang kedua tidak akan berfungsi.


Setelah klarifikasi Anda untuk pertanyaan dan komentar, saya pribadi akan menyatakan kembali jenis _item.Get ("001") ke ICollection. Ini berarti Anda tidak perlu melakukan casting atau konversi apa pun (melalui ToList / ToArray) yang akan melibatkan operasi buat / salin yang tidak perlu.

// 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++) 

Salam Hormat,

Dr. Andrew Burnett-Thompson
sumber
1
Tanda tangannya adalah: IEnumerable <T> Get (string pk); Item digunakan untuk menyimpan catatan Item yang dikembalikan. Kemudian saya mengulanginya untuk membuat laporan. Saya akan baik-baik saja menggunakan apa pun yang berhasil. Menurut Anda, jenis tipe data apa yang terbaik?
Samantha JT Star
1
Saya akan menyarankan untuk mengubah tipe data Item ke IEnumerable <T> agar sesuai dengan Get, atau mengubah tipe pengembalian Get to ICollection <T> untuk mencocokkan Item. Saya berasumsi keduanya adalah tipe dasar yang sama hanya dinyatakan berbeda? JIKA mereka adalah tipe yang sama Anda ingin menghindari penggunaan ToList () atau ToArray () karena itu melakukan alokasi memori yang tidak perlu dan salinan array. Jika mereka bukan tipe yang sama Anda harus melakukan beberapa pertobatan
Dr. Andrew Burnett-Thompson
Saya menambahkan pertanyaan untuk menunjukkan di mana saya nanti menggunakan Item. Anda benar saat mengatakan tipe dasar yang sama.
Samantha JT Star
Ok, maka saya hanya akan mengubah jenis pengembalian Get, karena Anda tidak perlu melakukan konversi apa pun (melalui ToList / ToArray, yang lambat), atau casting. Semoga ini bisa membantu :)
Dr. Andrew Burnett-Thompson