Katakanlah saya punya kelas
public class MyObject
{
public int SimpleInt{get;set;}
}
Dan saya punya List<MyObject>
, dan saya ToList()
dan kemudian mengubah salah satu SimpleInt
, akankah perubahan saya disebarkan kembali ke daftar asli. Dengan kata lain, apa yang akan menjadi hasil dari metode berikut?
public void RunChangeList()
{
var objs = new List<MyObject>(){new MyObject(){SimpleInt=0}};
var whatInt = ChangeToList(objs );
}
public int ChangeToList(List<MyObject> objects)
{
var objectList = objects.ToList();
objectList[0].SimpleInt=5;
return objects[0].SimpleInt;
}
Mengapa?
P / S: Saya minta maaf jika tampaknya jelas untuk mencari tahu. Tapi saya tidak punya kompiler dengan saya sekarang ...
.ToList()
membuat salinan yang dangkal . Referensi disalin, tetapi referensi baru masih menunjuk ke contoh yang sama dengan referensi asli menunjuk. Ketika Anda memikirkan hal itu,ToList
tidak dapat membuatnew MyObject()
saatMyObject
adalahclass
jenis.Jawaban:
Ya,
ToList
akan membuat daftar baru, tetapi karena dalam hal iniMyObject
adalah jenis referensi maka daftar baru akan berisi referensi ke objek yang sama dengan daftar asli.Memperbarui
SimpleInt
properti objek yang dirujuk dalam daftar baru juga akan mempengaruhi objek yang setara dalam daftar asli.(Jika
MyObject
dideklarasikan sebagaistruct
bukan dariclass
maka daftar baru akan berisi salinan elemen-elemen dalam daftar asli, dan memperbarui properti elemen dalam daftar baru tidak akan mempengaruhi elemen setara dalam daftar asli.)sumber
List
struct, tugas sepertiobjectList[0].SimpleInt=5
tidak akan diizinkan (kesalahan waktu kompilasi C #). Itu karena nilai balikget
accessor daftar pengindeks bukan variabel (itu adalah salinan yang dikembalikan dari nilai struct), dan oleh karena itu mengatur anggotanya.SimpleInt
dengan ekspresi penugasan tidak diperbolehkan (itu akan bermutasi salinan yang tidak disimpan) . Nah, siapa yang menggunakan struct yang bisa berubah?foreach (var s in listOfStructs) { s.SimpleInt = 42; }
. The benar-benar Gotcha jahat adalah ketika Anda mencoba sesuatu sepertilistOfStructs.ForEach(s => s.SimpleInt = 42)
: compiler memungkinkan dan berjalan kode tanpa pengecualian, tetapi struct dalam daftar akan tetap tidak berubah!Dari sumber Reflector'd:
Jadi ya, daftar asli Anda tidak akan diperbarui (yaitu penambahan atau penghapusan) namun objek yang dirujuk akan.
sumber
ToList
akan selalu membuat daftar baru, yang tidak akan mencerminkan perubahan berikutnya pada koleksi.Namun, itu akan mencerminkan perubahan pada objek itu sendiri (Kecuali jika mereka bisa berubah struktur).
Dengan kata lain, jika Anda mengganti objek dalam daftar asli dengan objek yang berbeda,
ToList
masih akan berisi objek pertama.Namun, jika Anda memodifikasi salah satu objek dalam daftar asli,
ToList
masih akan berisi objek yang sama (dimodifikasi).sumber
Jawaban yang diterima dengan benar menjawab pertanyaan OP berdasarkan pada contohnya. Namun, itu hanya berlaku saat
ToList
diterapkan pada koleksi beton; itu tidak berlaku ketika elemen-elemen dari urutan sumber belum dipakai (karena eksekusi ditangguhkan). Dalam hal yang terakhir, Anda mungkin mendapatkan set item baru setiap kali Anda meneleponToList
(atau menyebutkan urutannya).Berikut ini adalah adaptasi dari kode OP untuk menunjukkan perilaku ini:
Sementara kode di atas mungkin tampak dibuat-buat, perilaku ini dapat muncul sebagai bug halus dalam skenario lain. Lihat contoh saya yang lain untuk situasi di mana ia menyebabkan tugas-tugas muncul berulang kali.
sumber
Ya, itu membuat daftar baru. Ini dengan desain.
Daftar ini akan berisi hasil yang sama dengan urutan enumerable asli, tetapi terwujud menjadi koleksi persisten (dalam memori). Ini memungkinkan Anda untuk mengkonsumsi hasil beberapa kali tanpa mengeluarkan biaya mengkomputasi ulang urutan.
Keindahan dari urutan LINQ adalah bahwa mereka dapat dikomposasikan Seringkali, yang
IEnumerable<T>
Anda dapatkan adalah hasil dari menggabungkan beberapa penyaringan, pemesanan, dan / atau operasi proyeksi. Metode ekstensi menyukaiToList()
danToArray()
memungkinkan Anda untuk mengubah urutan yang dihitung menjadi koleksi standar.sumber
Daftar baru dibuat tetapi item di dalamnya adalah referensi ke item asli (seperti dalam daftar asli). Perubahan pada daftar itu sendiri adalah independen, tetapi untuk item akan menemukan perubahan di kedua daftar.
sumber
Baru saja menemukan posting lama ini dan berpikir untuk menambahkan dua sen saya. Secara umum, jika saya ragu, saya dengan cepat menggunakan metode GetHashCode () pada objek apa pun untuk memeriksa identitas. Jadi untuk di atas -
Dan jawab di mesin saya -
Jadi pada dasarnya objek yang dibawanya tetap sama dalam kode di atas. Semoga pendekatan ini membantu.
sumber
Saya pikir ini setara dengan menanyakan apakah ToList melakukan salinan yang dalam atau dangkal. Karena ToList tidak memiliki cara untuk mengkloning MyObject, ia harus melakukan salinan yang dangkal, sehingga daftar yang dibuat berisi referensi yang sama dengan yang asli, sehingga kode mengembalikan 5.
sumber
ToList
akan membuat daftar baru.Jika item dalam daftar adalah tipe nilai, mereka akan langsung diperbarui, jika mereka adalah tipe referensi, setiap perubahan akan tercermin kembali dalam objek yang direferensikan.
sumber
Dalam kasus di mana objek sumber adalah IEnumerable yang benar (yaitu bukan hanya kumpulan yang dikemas sebagai enumerable), ToList () mungkin TIDAK mengembalikan referensi objek yang sama seperti dalam IEnumerable asli. Ini akan mengembalikan daftar objek baru, tetapi objek-objek itu mungkin tidak sama atau bahkan sama dengan objek yang dihasilkan oleh IEnumerable ketika dienumerasi lagi
sumber
Ini akan memperbarui objek asli juga. Daftar baru akan berisi referensi ke objek yang terkandung di dalamnya, sama seperti daftar asli. Anda dapat mengubah elemen baik dan pembaruan akan tercermin di yang lain.
Sekarang jika Anda memperbarui daftar (menambah atau menghapus item) yang tidak akan tercermin dalam daftar lainnya.
sumber
Saya tidak melihat di mana pun dalam dokumentasi bahwa ToList () selalu dijamin untuk mengembalikan daftar baru. Jika IEnumerable adalah Daftar, mungkin lebih efisien untuk memeriksanya dan mengembalikan Daftar yang sama.
Kekhawatirannya adalah bahwa kadang-kadang Anda mungkin ingin benar-benar yakin bahwa Daftar yang dikembalikan adalah! = Ke Daftar asli. Karena Microsoft tidak mendokumentasikan ToList akan mengembalikan Daftar baru, kami tidak dapat memastikan (kecuali seseorang menemukan dokumentasi itu). Itu juga bisa berubah di masa depan, bahkan jika itu berfungsi sekarang.
Daftar baru (enumerablestuff IEnumerable) dijamin untuk mengembalikan Daftar baru. Saya akan menggunakan ini sebagai gantinya.
sumber
ToList
tampaknya membuat referensi objek daftar baru ketika dipanggil padaList
, BenB benar ketika ia mengatakan bahwa ini tidak dijamin oleh dokumentasi MS.IEnumerable<>.ToList()
sebenarnya diimplementasikannew List<>(source)
dan tidak ada penggantian khusus untukList<>
, jadiList<>.ToList()
memang mengembalikan referensi objek daftar baru. Tetapi sekali lagi, sesuai dokumentasi MS, tidak ada jaminan untuk ini tidak berubah di masa depan, meskipun kemungkinan akan merusak sebagian besar kode di luar sana.