Lihat program berikut:
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList(myList);
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList(List<int> myList)
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
Saya berasumsi myList
akan berlalu ref
, dan hasilnya akan
3
4
Daftar ini memang "disahkan oleh ref", tetapi hanya sort
fungsi yang berfungsi. Pernyataan berikut myList = myList2;
tidak berpengaruh.
Jadi outputnya sebenarnya:
10
50
100
Bisakah Anda membantu saya menjelaskan perilaku ini? Jika memang myList
tidak lewat-oleh-ref (seperti yang tampak dari myList = myList2
tidak berlaku), bagaimana myList.Sort()
efeknya?
Saya bahkan mengasumsikan pernyataan itu tidak berlaku dan hasilnya adalah:
100
50
10
c#
list
pass-by-reference
nmdr
sumber
sumber
ChangeList
mengembalikan aList<int>
daripada menjadivoid
jika sebenarnya membuat daftar baru.Jawaban:
Anda melewati sebuah referensi ke dalam daftar , tetapi Anda tidak melewati variabel daftar dengan referensi - sehingga ketika Anda menelepon
ChangeList
dengan nilai variabel (yaitu referensi - berpikir "pointer") disalin - dan perubahan pada nilai parameter di dalamnyaChangeList
tidak dilihat olehTestMethod
.mencoba:
Ini kemudian meneruskan referensi ke variabel lokal
myRef
(seperti yang dideklarasikan diTestMethod
); sekarang, jika Anda menetapkan kembali parameter di dalamChangeList
Anda juga menetapkan kembali variabel di dalamnyaTestMethod
.sumber
ChangeList
, hanya referensi yang disalin - itu adalah objek yang sama. Jika Anda mengubah objek dengan cara tertentu, semua yang memiliki referensi ke objek tersebut akan melihat perubahannya.Awalnya, ini dapat direpresentasikan secara grafis sebagai berikut:
Kemudian, pengurutan diterapkan
myList.Sort();
Akhirnya, ketika Anda melakukannya
myList' = myList2
:, Anda kehilangan salah satu referensi tetapi bukan yang asli dan koleksi tetap diurutkan.Jika Anda menggunakan by reference (
ref
) makamyList'
danmyList
akan menjadi sama (hanya satu referensi).Catatan: Saya gunakan
myList'
untuk mewakili parameter yang Anda gunakan diChangeList
(karena Anda memberi nama yang sama dengan aslinya)sumber
Berikut cara mudah untuk memahaminya
Daftar Anda adalah objek yang dibuat di heap. Variabel
myList
adalah referensi ke objek itu.Dalam C # Anda tidak pernah melewatkan objek, Anda meneruskan referensi mereka dengan nilai.
Saat Anda mengakses objek daftar melalui referensi yang diteruskan di
ChangeList
(saat menyortir, misalnya) daftar asli diubah.Penetapan pada
ChangeList
metode dibuat ke nilai referensi, oleh karena itu tidak ada perubahan yang dilakukan pada daftar asli (masih di heap tetapi tidak direferensikan pada variabel metode lagi).sumber
Link ini akan membantu Anda dalam memahami referensi lewat di C #. Pada dasarnya, ketika sebuah objek berjenis referensi diteruskan dengan nilai ke suatu metode, hanya metode yang tersedia pada objek itu yang dapat mengubah konten objek.
Misalnya metode List.sort () mengubah konten Daftar tetapi jika Anda menetapkan beberapa objek lain ke variabel yang sama, tugas itu bersifat lokal untuk metode itu. Itulah mengapa myList tetap tidak berubah.
Jika kita melewatkan objek tipe referensi dengan menggunakan kata kunci ref maka kita dapat menetapkan beberapa objek lain ke variabel yang sama dan itu mengubah seluruh objek itu sendiri.
(Sunting: ini adalah versi terbaru dari dokumentasi yang ditautkan di atas.)
sumber
C # hanya melakukan salinan dangkal ketika melewati nilai kecuali objek yang dimaksud dieksekusi
ICloneable
(yang tampaknya tidak olehList
kelas).Artinya, ia menyalin
List
dirinya sendiri, tetapi referensi ke objek di dalam daftar tetap sama; artinya, penunjuk terus merujuk objek yang sama seperti aslinyaList
.Jika Anda mengubah nilai dari hal-hal yang menjadi
List
referensi baru Anda, Anda juga mengubah yang asliList
(karena merujuk pada objek yang sama). Namun, Anda kemudian mengubahmyList
referensi apa seluruhnya, menjadi yang baruList
, dan sekarang hanya yang asliList
yang mereferensikan bilangan bulat tersebut.Baca bagian Parameter Jenis Referensi Melewati dari artikel MSDN ini di "Parameter yang Melewati" untuk informasi lebih lanjut.
"Bagaimana cara Mengkloning Daftar Generik di C #" dari StackOverflow berbicara tentang cara membuat salinan dalam Daftar.
sumber
Sementara saya setuju dengan apa yang dikatakan semua orang di atas. Saya memiliki pandangan berbeda tentang kode ini. Pada dasarnya Anda menetapkan daftar baru ke variabel lokal myList bukan global. jika Anda mengubah tanda tangan ChangeList (List myList) menjadi private void ChangeList (), Anda akan melihat output 3, 4.
Inilah alasan saya ... Meskipun list dilewatkan oleh referensi, anggap saja sebagai melewatkan variabel pointer dengan nilai Ketika Anda memanggil ChangeList (myList) Anda meneruskan pointer ke (Global) myList. Sekarang ini disimpan di variabel myList (lokal). Jadi sekarang myList (lokal) dan (global) myList Anda mengarah ke daftar yang sama. Sekarang Anda melakukan sort => ini berfungsi karena (lokal) myList mereferensikan myList (global) asli. Selanjutnya Anda membuat daftar baru dan menetapkan pointer ke myList (lokal) Anda. Tapi begitu fungsi keluar, variabel (lokal) myList dihancurkan. HTH
sumber
Gunakan
ref
kata kunci.Lihat referensi definitif di sini untuk memahami parameter yang lewat.
Untuk lebih spesifik, lihat ini , untuk memahami perilaku kode.
EDIT:
Sort
bekerja pada referensi yang sama (yang dilewatkan oleh nilai) dan karenanya nilainya diurutkan. Namun, menetapkan contoh baru ke parameter tidak akan berfungsi karena parameter diteruskan oleh nilai, kecuali Anda memasukkanref
.Puting
ref
memungkinkan Anda mengubah penunjuk ke referensi ke contoh baruList
dalam kasus Anda. Tanpanyaref
, Anda dapat mengerjakan parameter yang ada, tetapi tidak dapat membuatnya menunjuk ke sesuatu yang lain.sumber
Ada dua bagian memori yang dialokasikan untuk objek tipe referensi. Satu di tumpukan dan satu lagi di tumpukan. Bagian dalam tumpukan (alias pointer) berisi referensi ke bagian dalam heap - tempat menyimpan nilai aktual.
Jika kata kunci ref tidak digunakan, hanya salinan bagian dalam tumpukan yang dibuat dan diteruskan ke metode - referensi ke bagian yang sama di heap. Oleh karena itu, jika Anda mengubah sesuatu di bagian heap, perubahan itu akan tetap ada. Jika Anda mengubah penunjuk yang disalin - dengan menetapkannya untuk merujuk ke tempat lain di heap - ini tidak akan memengaruhi penunjuk asal di luar metode.
sumber