Apa perbedaan antara tipe referensi dan tipe nilai di c #?

100

Beberapa pria menanyakan pertanyaan ini kepada saya beberapa bulan yang lalu dan saya tidak dapat menjelaskannya secara detail. Apa perbedaan antara tipe referensi dan tipe nilai di C #?

Saya tahu bahwa jenis nilai yang int, bool, float, dll dan referensi jenis yang delegate, interface, dll Atau salah ini, juga?

Bisakah Anda menjelaskannya kepada saya secara profesional?

tugberk
sumber
3
Sebagai catatan kecil, saya pikir pertanyaan yang diajukan tentang C #, tetapi kenyataannya ini tentang C # + .NET. Anda tidak dapat menganalisis C # tanpa menganalisis .NET. Saya tidak akan memberi tag ulang pada pertanyaan karena mungkin ada beberapa poin yang harus dibuat untuk menganalisis satu tanpa menganalisis yang lain (iterator dan penutupan, saya melihat Anda)
xanatos
@xanatos itu adalah pertanyaan yang paling tepat tentang CLI yang memiliki kesamaan di C #, VB.Net dan, Net. Harus ada tag untuk CLI tetapi CLI diambil untuk sesuatu yang lain. Ada CLR tapi itu implementasi, bukan standar.
pengguna34660

Jawaban:

172

Contoh Anda agak aneh karena sementara int, booldan floatmerupakan tipe tertentu, antarmuka dan delegasi adalah tipe tipe - sama seperti structdan enummerupakan tipe tipe nilai.

Saya telah menulis sebuah penjelasan tentang jenis referensi dan jenis nilai dalam artikel ini . Saya akan dengan senang hati menjelaskan setiap bagian yang menurut Anda membingungkan.

Versi "TL; DR" adalah memikirkan apa nilai variabel / ekspresi dari tipe tertentu. Untuk tipe nilai, nilainya adalah informasi itu sendiri. Untuk tipe referensi, nilainya adalah referensi yang mungkin nihil atau mungkin merupakan cara untuk menavigasi ke objek yang berisi informasi.

Misalnya, anggap variabel seperti selembar kertas. Itu bisa memiliki nilai "5" atau "false" yang tertulis di atasnya, tapi tidak bisa rumah saya ... itu harus memiliki petunjuk arah ke rumah saya. Arah tersebut setara dengan referensi. Secara khusus, dua orang dapat memiliki potongan kertas berbeda yang berisi petunjuk arah yang sama ke rumah saya - dan jika satu orang mengikuti petunjuk tersebut dan mengecat rumah saya dengan warna merah, orang kedua akan melihat perubahan itu juga. Jika mereka berdua hanya memiliki gambar terpisah dari rumah saya di atas kertas, maka satu orang yang mewarnai kertas mereka tidak akan mengubah kertas orang lain sama sekali.

Jon Skeet
sumber
2
Penting untuk diperhatikan bahwa ada tiga jenis utama semantik yang berbeda yang dapat ditawarkan: semantik yang tidak dapat diubah, semantik nilai yang dapat berubah, dan semantik referensi yang dapat diubah. Secara konseptual, jenis semantik yang diimplementasikan sesuatu adalah ortogonal baik itu disimpan sebagai objek heap mandiri atau variabel / bidang (struct). Dalam praktiknya, sementara struct yang tidak mengekspos bidangnya dapat menerapkan segala jenis semantik, fakta bahwa .net memungkinkan berbagi referensi heap secara sembarangan berarti objek heap tidak dapat mengimplementasikan semantik nilai yang dapat berubah.
supercat
Saya tidak mengerti sedikit ini - while int, bool and float are specific types, interfaces and delegates are kinds of type - just like struct and enum are kinds of value types. Apa yang Anda maksud dengan int, bool menjadi tipe tertentu? Segala sesuatu di C # misalnya int, bool, float, class, interface, delegate adalah tipe (tipe data tepatnya). Jenis data dipisahkan sebagai 'Jenis Referensi' dan 'Jenis Nilai' di C #. Lalu mengapa Anda mengatakan int adalah tipe tertentu tetapi antarmuka adalah jenis tipe?
RBT
2
@RBT: Jenis data tidak hanya dipisahkan menjadi "jenis referensi" dan "jenis nilai". Mereka juga dipisahkan menjadi "class, struct, enum, delegate, interface". intadalah struct, stringadalah kelas, Actionadalah delegasi, dll. Daftar "int, bool, float, class, interface, delegate" adalah daftar yang berisi berbagai macam hal, dengan cara yang sama seperti "10, int" adalah daftar yang berisi berbagai jenis hal.
Jon Skeet
@JonSkeet Mungkin jawaban postingan ini agak menyesatkan.
RBT
@RBT: Saya akan mengatakan itu kata-kata yang agak buruk, tapi tidak mengerikan.
Jon Skeet
26

Jenis nilai:

Memegang beberapa nilai bukan alamat memori

Contoh:

Struct

Penyimpanan:

TL; DR : Nilai variabel disimpan di mana pun ia dideklarasikan. Variabel lokal hidup di tumpukan misalnya, tetapi ketika dideklarasikan di dalam kelas sebagai anggota, ia tinggal di heap yang digabungkan erat dengan kelas tempat ia dideklarasikan.
Longer : Jadi tipe nilai disimpan di mana pun mereka dideklarasikan. Misalnya: nilai an intdi dalam fungsi sebagai variabel lokal akan disimpan di stack, sementara intnilai in yang dideklarasikan sebagai anggota dalam kelas akan disimpan di heap dengan kelas tempat ia dideklarasikan. Jenis nilai pada sebuah kelas memiliki jenis kehidupan yang persis sama dengan kelas yang dideklarasikan, hampir tidak memerlukan pekerjaan oleh pengumpul sampah. Ini lebih rumit, saya akan merujuk ke buku @ JonSkeet " C # In Depth "Memori dalam .NET"untuk penjelasan yang lebih ringkas.

Keuntungan:

Jenis nilai tidak membutuhkan pengumpulan sampah tambahan. Itu mendapatkan sampah yang dikumpulkan bersama dengan instance tempat tinggalnya. Variabel lokal dalam metode dibersihkan setelah metode pergi.

Kekurangan:

  1. Ketika sejumlah besar nilai diteruskan ke metode, variabel penerima sebenarnya menyalin sehingga ada dua nilai yang berlebihan dalam memori.

  2. Karena kelas terlewat. Itu kehilangan semua manfaat luar

Jenis referensi:

Menyimpan alamat memori dengan nilai bukan nilai

Contoh:

Kelas

Penyimpanan:

Disimpan di heap

Keuntungan:

  1. Ketika Anda meneruskan variabel referensi ke metode dan itu mengubahnya memang mengubah nilai asli sedangkan dalam tipe nilai salinan variabel yang diberikan diambil dan nilai itu diubah.

  2. Jika ukuran variabel lebih besar, tipe referensi bagus

  3. Karena kelas datang sebagai variabel jenis referensi, mereka memberikan usabilitas, sehingga menguntungkan pemrograman berorientasi objek

Kekurangan:

Lebih banyak referensi pekerjaan saat mengalokasikan dan dereferensi saat membaca overload value.extra untuk pengumpul sampah

Durai Amuthan.H
sumber
5
Jenis referensi tidak selalu benar bahwa jenis referensi disimpan di heap, dan jenis nilai disimpan di stack. Baca yoda.arachsys.com/csharp/memory.html jika Anda ingin mempelajari lebih lanjut.
Rhys
1
Ada banyak kesalahpahaman dalam jawaban ini. Silakan baca Jeff Richters CLR melalui C #. Jenis Nilai disimpan di Thread Stack dan tidak tunduk pada pengumpulan sampah (GC) - tidak ada hubungannya dengan GC. Jenis Referensi disimpan di heap terkelola dan karenanya tunduk pada GC. Jika Jenis Referensi memiliki referensi root, ia tidak dapat dikumpulkan dan dipromosikan dari generasi ke generasi, 0, 1 & 2. Jika tidak memiliki referensi root, ia dapat Dikumpulkan Sampah & kemudian melalui proses ini yang disebut Kebangkitan di mana ia dibunuh dan dihidupkan kembali dan akhirnya dikumpulkan.
Jeremy Thompson
13

Saya merasa lebih mudah untuk memahami perbedaan keduanya jika Anda tahu bagaimana komputer mengalokasikan barang dalam memori dan tahu apa itu pointer.

Referensi biasanya dikaitkan dengan penunjuk. Artinya alamat memori tempat variabel Anda berada sebenarnya menyimpan alamat memori lain dari objek sebenarnya di lokasi memori yang berbeda.

Contoh yang akan saya berikan terlalu disederhanakan, jadi ambillah dengan sebutir garam.

Bayangkan memori komputer adalah sekumpulan PO box dalam satu baris (mulai dengan PO Box 0001 hingga PO Box n) yang dapat menampung sesuatu di dalamnya. Jika PO box tidak melakukannya untuk Anda, coba hashtable atau kamus atau larik atau yang serupa.

Jadi, ketika Anda melakukan sesuatu seperti:

var a = "Halo";

komputer akan melakukan hal berikut:

  1. alokasikan memori (katakanlah mulai dari lokasi memori 1000 untuk 5 byte) dan masukkan H (pada 1000), e (pada 1001), l (pada 1002), l (pada 1003) dan o (pada 1004).
  2. mengalokasikan suatu tempat dalam memori (katakanlah di lokasi 0500) dan menugaskannya sebagai variabel a.
    Jadi ini semacam alias (0500 adalah a).
  3. tetapkan nilai di lokasi memori itu (0500) ke 1000 (di mana string Hello mulai di memori). Jadi, variabel a memegang referensi ke lokasi memori awal sebenarnya dari string "Hello".

Jenis nilai akan menyimpan hal yang sebenarnya di lokasi memorinya.

Jadi, ketika Anda melakukan sesuatu seperti:

var a = 1;

komputer akan melakukan hal berikut:

  1. mengalokasikan lokasi memori katakan pada 0500 dan tetapkan ke variabel a (alias yang sama)
  2. letakkan nilai 1 di dalamnya (di lokasi memori 0500).
    Perhatikan bahwa kami tidak mengalokasikan memori tambahan untuk menampung nilai sebenarnya (1). Jadi a sebenarnya memegang nilai sebenarnya dan itulah mengapa disebut tipe nilai.
Jimmy Chandra
sumber
1
Anda mungkin tertarik dengan blogs.msdn.com/b/ericlippert/archive/2009/02/17/…
Jon Skeet
@ Jon, Nah, hal semacam itu membatalkan apa yang saya katakan, LOL. Tapi seperti yang saya katakan, terlalu disederhanakan untuk mendapatkan pemahaman antara dua jenis yang dalam kasus saya menurut saya berguna. Setidaknya begitulah cara saya membayangkannya dalam pikiran saya :).
Jimmy Chandra
8

Ini dari postingan saya dari forum yang berbeda, sekitar dua tahun lalu. Meskipun bahasanya adalah vb.net (kebalikan dari C #), konsep Tipe Nilai vs. tipe Referensi seragam di seluruh .net, dan contoh masih berlaku.

Penting juga untuk diingat bahwa dalam .net, SEMUA tipe secara teknis diturunkan dari tipe dasar Object. Tipe nilai dirancang untuk berperilaku seperti itu, tetapi pada akhirnya mereka juga mewarisi fungsionalitas Objek tipe dasar.

A. Tipe Nilai hanyalah bahwa- mereka mewakili area yang berbeda dalam memori di mana sebuah NILAI diskrit disimpan. Jenis nilai memiliki ukuran memori tetap dan disimpan dalam tumpukan, yang merupakan kumpulan alamat dengan ukuran tetap.

Ketika Anda membuat pernyataan seperti itu:

Dim A as Integer
DIm B as Integer

A = 3
B = A 

Anda telah melakukan hal berikut:

  1. Dibuat 2 ruang di memori yang cukup untuk menampung nilai integer 32 bit.
  2. Menempatkan nilai 3 di alokasi memori yang ditetapkan ke A
  3. Menempatkan nilai 3 di alokasi memori yang ditetapkan ke B dengan menetapkannya nilai yang sama seperti yang disimpan di A.

Nilai setiap variabel ada secara terpisah di setiap lokasi memori.

B. Jenis Referensi dapat dalam berbagai ukuran. Oleh karena itu, mereka tidak dapat disimpan di "Stack" (ingat, stack adalah kumpulan alokasi memori dengan ukuran tetap?). Mereka disimpan di "Heap Terkelola". Pointer (atau "referensi") ke setiap item di heap terkelola dipertahankan dalam tumpukan (Seperti Alamat). Kode Anda menggunakan petunjuk ini dalam tumpukan untuk mengakses objek yang disimpan di heap terkelola. Jadi, saat kode Anda menggunakan variabel referensi, sebenarnya kode tersebut menggunakan pointer (atau "alamat" ke lokasi memori di heap terkelola).

Katakanlah Anda telah membuat Kelas bernama clsPerson, dengan string Property Person.Name

Dalam hal ini, ketika Anda membuat pernyataan seperti ini:

Dim p1 As clsPerson
p1 = New clsPerson
p1.Name = "Jim Morrison"

Dim p2 As Person

p2 = p1

Dalam kasus di atas, Properti p1.Name akan Mengembalikan "Jim Morrison", seperti yang Anda harapkan. Properti p2.Name JUGA akan mengembalikan "Jim Morrison", seperti yang Anda harapkan secara intuitif. Saya yakin bahwa p1 dan p2 mewakili alamat yang berbeda di Stack. Namun, sekarang setelah Anda menetapkan p2 nilai p1, p1 dan p2 menunjuk ke LOKASI YANG SAMA di heap terkelola.

Sekarang pertimbangkan situasi INI:

Dim p1 As clsPerson
Dim p2 As clsPerson

p1 = New clsPerson
p1.Name = "Jim Morrison"

p2 = p1

p2.Name = "Janis Joplin"

Dalam situasi ini, Anda telah membuat satu contoh baru dari kelas orang di Heap Terkelola dengan penunjuk p1 di Tumpukan yang mereferensikan objek, dan menetapkan Properti Nama contoh objek nilai "Jim Morrison" lagi. Selanjutnya, Anda membuat pointer lain p2 di Stack, dan mengarahkannya ke alamat yang sama di heap terkelola seperti yang direferensikan oleh p1 (saat Anda membuat tugas p2 = p1).

Inilah twistnya. Ketika Anda menetapkan properti Nama p2 nilai "Janis Joplin" Anda mengubah properti Nama untuk objek REFERENSI oleh p1 dan p2, sehingga, jika Anda menjalankan kode berikut:

MsgBox(P1.Name)
'Will return "Janis Joplin"

MsgBox(p2.Name)
'will ALSO return "Janis Joplin"Because both variables (Pointers on the Stack) reference the SAME OBJECT in memory (an Address on the Managed Heap). 

Apakah itu masuk akal?

Terakhir. Jika kamu melakukan ini:

DIm p1 As New clsPerson
Dim p2 As New clsPerson

p1.Name = "Jim Morrison"
p2.Name = "Janis Joplin"

Anda sekarang memiliki dua Objek Orang yang berbeda. Namun, begitu Anda melakukan INI lagi:

p2 = p1

Anda sekarang telah mengarahkan keduanya kembali ke "Jim Morrison". (Saya tidak begitu yakin apa yang terjadi pada Objek di Heap yang direferensikan oleh p2 ... Saya BERPIKIR sekarang sudah keluar dari ruang lingkup. Ini adalah salah satu area di mana semoga seseorang dapat meluruskan saya ...). -EDIT: SAYA PERCAYA inilah mengapa Anda harus Set p2 = Nothing OR p2 = New clsPerson sebelum membuat tugas baru.

Sekali lagi, jika Anda sekarang melakukan INI:

p2.Name = "Jimi Hendrix"

MsgBox(p1.Name)
MsgBox(p2.Name)

Kedua msgBox sekarang akan menampilkan "Jimi Hendrix"

Ini bisa sedikit membingungkan, dan saya akan mengatakan untuk terakhir kalinya, saya mungkin memiliki beberapa detail yang salah.

Good Luck, dan semoga orang lain yang lebih tahu dari saya akan datang untuk membantu mengklarifikasi beberapa hal ini. . .

XIVSolutions
sumber
Saya tidak tahu mengapa Anda tidak menerima suara positif. Jawaban yang bagus, membantu saya memahami dengan contoh yang jelas dan sederhana.
Harry
Adapun konsep Tipe Nilai vs. Tipe referensi seragam di seluruh .net, mereka sebenarnya didefinisikan dalam spesifikasi Common Language Infrastructure (CLI), standar Ecma 335 (juga standar ISO). Itu adalah standar untuk bagian standar .Net. Standar Ecma 334 (juga standar ISO) adalah bahasa C # dan menyatakan secara eksplisit bahwa implementasi C # harus bergantung pada CLI atau mendukung cara alternatif untuk mendapatkan fitur CLI minimum yang disyaratkan oleh standar C # ini . Namun VB.Net bukan standar, itu adalah milik Microsoft.
pengguna34660
5

tipe data nilai dan tipe data referensi

1) nilai (berisi data secara langsung) tetapi referensi (mengacu pada data)

2) dalam nilai (setiap variabel memiliki salinannya sendiri) tetapi
dalam referensi (lebih dari variabel dapat merujuk ke beberapa objek)

3) dalam nilai (variabel operasi tidak dapat berpengaruh pada variabel lain) tetapi dalam referensi (variabel dapat mempengaruhi lainnya)

4) tipe nilai adalah (int, bool, float) tetapi tipe referensi adalah (array, objek kelas, string)

Mohamed Elmasry
sumber
2

Jenis Nilai:

  • Ukuran memori tetap.

  • Disimpan dalam memori Stack.

  • Memiliki nilai sebenarnya.

    Ex. int, char, bool, dll ...

Jenis Referensi:

  • Bukan memori tetap.

  • Disimpan dalam memori Heap.

  • Menyimpan alamat memori dari nilai sebenarnya.

    Ex. string, array, kelas, dll ...

Dhinagaran P.
sumber
1

"Variabel yang didasarkan pada jenis nilai secara langsung berisi nilai. Menetapkan satu variabel jenis nilai ke variabel lain akan menyalin nilai yang terkandung. Ini berbeda dengan penetapan variabel jenis referensi, yang menyalin referensi ke objek tetapi tidak ke objek itu sendiri." dari perpustakaan Microsoft.

Anda dapat menemukan jawaban yang lebih lengkap di sini dan di sini .

Lucas S.
sumber
1
Saya tidak suka penjelasan itu, karena sepertinya tugas bekerja berbeda untuk tipe referensi dan tipe nilai. Tidak. Dalam kedua kasus, ini membuat nilai variabel "target" sama dengan ekspresi - nilainya disalin. The perbedaan dalam nilai apa yang - untuk referensi jenis, nilai yang akan disalin adalah referensi. Itu masih nilai variabelnya.
Jon Skeet
Saya setuju dengan Anda dan saya sudah tahu bahwa ini mungkin saja berbeda, seperti yang dapat Anda baca di artikel ini . Tapi, saya hanya mengulang panduan Microsoft tentang subjek dan juga cara Anda biasanya membaca di buku. Tolong jangan salahkan saya! :)
Lucas S.
Oh tentu ... ada banyak dokumentasi MSDN di mana ada kesalahan yang bisa ditemukan :)
Jon Skeet
1

Terkadang penjelasan tidak akan membantu terutama untuk pemula. Anda dapat membayangkan tipe nilai sebagai file data dan tipe referensi sebagai pintasan ke file.

Jadi jika Anda menyalin variabel referensi, Anda hanya menyalin tautan / penunjuk ke data nyata di suatu tempat di memori. Jika Anda menyalin tipe nilai, Anda benar-benar mengkloning data di memori.

Nime Cloud
sumber
0

Ini mungkin salah dalam hal esoteris, tetapi, untuk membuatnya sederhana:

Jenis nilai adalah nilai yang diteruskan secara normal "menurut nilai" (jadi menyalinnya). Jenis referensi diteruskan "dengan referensi" (jadi memberikan penunjuk ke nilai asli). Tidak ada jaminan apa pun oleh standar ECMA .NET di mana "hal-hal" ini disimpan. Anda dapat membangun implementasi .NET yang tanpa tumpukan, atau yang tanpa tumpukan (yang kedua akan sangat rumit, tetapi Anda mungkin bisa, menggunakan serat dan banyak tumpukan)

Struktur adalah tipe nilai (int, bool ... adalah struct, atau setidaknya disimulasikan sebagai ...), kelas adalah tipe referensi.

Jenis nilai diturunkan dari System.ValueType. Jenis referensi turun dari System.Object.

Sekarang .. Pada akhirnya Anda memiliki Jenis Nilai, "objek yang direferensikan" dan referensi (dalam C ++ mereka akan disebut penunjuk ke objek. Dalam .NET mereka buram. Kami tidak tahu apa itu. Dari sudut pandang kami, mereka adalah "pegangan" ke objek). Yang terakhir ini mirip dengan Jenis Nilai (mereka diteruskan dengan salinan). Jadi sebuah objek disusun oleh objek (tipe referensi) dan nol atau lebih referensi ke sana (yang mirip dengan tipe nilai). Jika tidak ada referensi, GC mungkin akan mengumpulkannya.

Secara umum (dalam implementasi "default" dari .NET), Jenis nilai dapat ditempatkan di tumpukan (jika merupakan kolom lokal) atau di heap (jika merupakan kolom kelas, jika merupakan variabel dalam fungsi iterator, jika mereka adalah variabel yang direferensikan oleh closure, jika mereka adalah variabel dalam fungsi async (menggunakan Async CTP yang lebih baru) ...). Nilai yang direferensikan hanya dapat masuk ke heap. Referensi menggunakan aturan yang sama seperti tipe Nilai.

Dalam kasus Tipe Nilai yang berada di heap karena berada dalam fungsi iterator, fungsi asinkron, atau direferensikan oleh closure, jika Anda melihat file yang dikompilasi, Anda akan melihat bahwa kompilator membuat kelas untuk meletakkan variabel-variabel ini , dan kelas dibuat saat Anda memanggil fungsi tersebut.

Sekarang, saya tidak tahu bagaimana menulis hal-hal yang panjang, dan saya memiliki hal-hal yang lebih baik untuk dilakukan dalam hidup saya. Jika Anda menginginkan versi yang "tepat" "akademis" "benar", baca INI:

http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx

Ini 15 menit saya mencarinya! Ini lebih baik daripada versi msdn, karena ini adalah artikel "siap digunakan" yang ringkas.

xanatos.dll
sumber
1
Itu salah dalam lebih dari cara esoteris. Ini pada dasarnya salah menurut saya - karena nilai jenis referensi masih diteruskan oleh nilai juga; hanya saja nilainya adalah referensi, bukan objek. Lihat pobox.com/~skeet/csharp/parameters.html . Oh, dan variabel lokal bisa berakhir di heap juga, misalnya jika diambil atau menjadi bagian dari blok iterator.
Jon Skeet
Blok Iterator diubah menjadi kelas, jadi "di belakang Anda" ada "bidang kelas". Sama untuk penutupan. Ya ... Saya lupa menulis perbedaan antara "penunjuk" (referensi) dan "menunjuk"
xanatos
@xanatos: Tentu, itu adalah bidang kelas setelah kompilasi - tetapi mereka masih variabel lokal dalam kode sumber. Saya juga tidak akan menyebut referensi itu sendiri sebagai "tipe nilai" - saya rasa saya tahu dari mana Anda berasal, tetapi menurut saya tidak baik untuk membuat air berlumpur dengan cara ini.
Jon Skeet
@ Jon Ya ... Ini adalah tipe ketiga, karena pointer "buram" dalam .net, dan tidak berasal dari ValueType. Tetapi mereka lebih mirip dengan tipe nilai daripada referensi. Anda bisa "ref" dan "out" mereka. Saya harus mengotori air karena "seseorang" harus mengecoh cara kerja iterator.
xanatos
Melihat artikel yang sekarang saya tunjuk, saya telah menemukan: "Ada tiga jenis nilai: (1) contoh tipe nilai, (2) contoh tipe referensi, dan (3) referensi. (Kode di C # tidak dapat memanipulasi contoh jenis referensi secara langsung; itu selalu dilakukan melalui referensi. Dalam kode yang tidak aman, jenis penunjuk diperlakukan seperti jenis nilai untuk tujuan menentukan persyaratan penyimpanan nilainya. ) ".
xanatos
0

Cara termudah untuk memikirkan jenis referensi adalah dengan menganggapnya sebagai "ID objek"; satu-satunya hal yang dapat dilakukan dengan ID objek adalah membuat satu, menyalin satu, menanyakan atau memanipulasi tipe satu, atau membandingkan dua untuk persamaan. Upaya untuk melakukan hal lain dengan ID objek akan dianggap sebagai cara cepat untuk melakukan tindakan yang ditunjukkan dengan objek yang dirujuk oleh id tersebut.

Misalkan saya memiliki dua variabel X dan Y tipe Mobil - tipe referensi. Y kebetulan memiliki "ID objek # 19531". Jika saya mengatakan "X = Y", itu akan menyebabkan X menyimpan "ID objek # 19531". Perhatikan bahwa baik X maupun Y tidak memiliki mobil. Mobil, atau dikenal sebagai "ID objek # 19531", disimpan di tempat lain. Ketika saya menyalin Y ke X, yang saya lakukan hanyalah menyalin nomor ID. Sekarang misalkan saya mengatakan X.Color = Colors.Blue. Pernyataan seperti itu akan dianggap sebagai instruksi untuk mencari "ID objek # 19531" dan mengecatnya dengan warna biru. Perhatikan bahwa meskipun X dan Y sekarang merujuk ke mobil biru daripada kuning, pernyataan itu sebenarnya tidak memengaruhi X atau Y, karena keduanya masih mengacu pada "ID objek # 19531", yang masih mobil yang sama seperti itu selalu begitu.

supercat
sumber
0

Jenis variabel dan Nilai Referensi mudah diterapkan dan diterapkan dengan baik pada model domain, memfasilitasi proses pengembangan.

Untuk menghilangkan mitos apapun seputar jumlah "tipe nilai", saya akan berkomentar tentang bagaimana hal ini ditangani di platform. NET, khususnya di C # (CSharp) ketika dipanggil APIS dan mengirim parameter berdasarkan nilai, dengan referensi, dalam metode kami, dan fungsi dan bagaimana membuat perlakuan yang benar dari bagian-bagian dari nilai-nilai ini.

Baca artikel ini Nilai Jenis Variabel dan Referensi di C #

Marcelo Cavalini
sumber
Ini adalah situs Tanya Jawab hanya dalam bahasa Inggris, sayangnya = \. Namun, terima kasih telah mencoba menjawab. Harap buat jawaban lengkap, dengan tautan sebagai bantuan saja (tetapi bukan sebagai jawaban penuh berkelanjutan). Silakan lihat bagaimana menjawabnya .
Jesse
0

Misalkan vadalah ekspresi / variabel tipe nilai, dan rmerupakan ekspresi / variabel tipe referensi

    x = v  
    update(v)  //x will not change value. x stores the old value of v

    x = r 
    update(r)  //x now refers to the updated r. x only stored a link to r, 
               //and r can change but the link to it doesn't .

Jadi, variabel tipe nilai menyimpan nilai sebenarnya (5, atau "h"). Variabel tipe referensi hanya menyimpan tautan ke kotak metaforis di mana nilainya berada.

Anas Elghafari
sumber
0

Sebelum menjelaskan tipe data berbeda yang tersedia di C #, penting untuk menyebutkan bahwa C # adalah bahasa yang diketik dengan kuat. Ini berarti bahwa setiap variabel, konstanta, parameter masukan, tipe kembalian dan secara umum setiap ekspresi yang dievaluasi ke suatu nilai, memiliki tipe.

Setiap tipe berisi informasi yang akan disematkan oleh kompilator ke dalam file yang dapat dieksekusi sebagai metadata yang akan digunakan oleh runtime bahasa umum (CLR) untuk menjamin keamanan tipe ketika mengalokasikan dan mengambil kembali memori.

Jika Anda ingin mengetahui berapa banyak memori yang dialokasikan oleh tipe tertentu, Anda dapat menggunakan ukuran operator sebagai berikut:

static void Main()
{
    var size = sizeof(int);
    Console.WriteLine($"int size:{size}");
    size = sizeof(bool);
    Console.WriteLine($"bool size:{size}");
    size = sizeof(double);
    Console.WriteLine($"double size:{size}");
    size = sizeof(char);
    Console.WriteLine($"char size:{size}");
}

Keluarannya akan menunjukkan jumlah byte yang dialokasikan oleh setiap variabel.

int size:4
bool size:1
double size:8
char size:2

Informasi yang terkait dengan masing-masing jenis adalah:

  • Ruang penyimpanan yang dibutuhkan.
  • Nilai maksimum dan minimum. Misalnya, tipe Int32 menerima nilai antara 2147483648 dan 2147483647.
  • Jenis dasar yang diwarisi.
  • Lokasi di mana memori untuk variabel akan dialokasikan pada waktu proses.
  • Jenis operasi yang diizinkan.
  • Anggota (metode, bidang, acara, dll.) Yang ada dalam tipe. Misalnya, jika kita memeriksa definisi tipe int, kita akan menemukan struct dan anggota berikut:

    namespace System
    {
        [ComVisible(true)]
        public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<Int32>, IEquatable<Int32>
        {      
            public const Int32 MaxValue = 2147483647;     
            public const Int32 MinValue = -2147483648;
            public static Int32 Parse(string s, NumberStyles style, IFormatProvider provider);    
            ... 
        }  
    }

Manajemen memori Ketika beberapa proses berjalan pada sistem operasi dan jumlah RAM tidak cukup untuk menampung semuanya, sistem operasi memetakan bagian hard disk dengan RAM dan mulai menyimpan data di hard disk. Sistem operasi akan menggunakan tabel tertentu di mana alamat virtual dipetakan ke alamat fisik koresponden mereka untuk melakukan permintaan. Kemampuan untuk mengatur memori ini disebut memori virtual.

Dalam setiap proses, memori virtual yang tersedia diatur dalam 6 bagian berikut, tetapi untuk relevansi topik ini, kami hanya akan fokus pada tumpukan dan heap.

Tumpukan Tumpukan adalah struktur data LIFO (masuk terakhir, keluar pertama), dengan ukuran bergantung pada sistem operasi (secara default, untuk mesin ARM, x86 dan x64, Windows mencadangkan 1MB, sedangkan Linux memesan dari 2MB hingga 8MB tergantung pada Versi: kapan).

Bagian memori ini secara otomatis dikelola oleh CPU. Setiap kali suatu fungsi mendeklarasikan variabel baru, kompilator mengalokasikan blok memori baru sebesar ukurannya pada tumpukan, dan ketika fungsi selesai, blok memori untuk variabel tersebut dibatalkan alokasinya.

Tumpukan Wilayah memori ini tidak dikelola secara otomatis oleh CPU dan ukurannya lebih besar dari tumpukan. Ketika kata kunci baru dipanggil, kompilator mulai mencari blok memori bebas pertama yang sesuai dengan ukuran permintaan. dan ketika menemukannya, itu ditandai sebagai dicadangkan dengan menggunakan fungsi malloc () C bawaan dan mengembalikan penunjuk ke lokasi itu. Mungkin juga untuk membatalkan alokasi blok memori dengan menggunakan fungsi C bawaan free (). Mekanisme ini menyebabkan fragmentasi memori dan harus menggunakan pointer untuk mengakses blok memori yang tepat, ini lebih lambat daripada stack untuk melakukan operasi baca / tulis.

Tipe Khusus dan Bawaan Meskipun C # menyediakan satu set standar tipe bawaan yang mewakili bilangan bulat, boolean, karakter teks, dan seterusnya, Anda dapat menggunakan konstruksi seperti struct, class, antarmuka, dan enum untuk membuat tipe Anda sendiri.

Contoh tipe kustom menggunakan konstruksi struct adalah:

struct Point
{
    public int X;
    public int Y;
};

Tipe nilai dan referensi Kita dapat mengkategorikan tipe C # ke dalam kategori berikut:

  • Jenis nilai
  • Jenis referensi

Jenis nilai nilai berasal dari kelas System.ValueType dan variabel tipe ini berisi nilai mereka dalam alokasi memorinya di tumpukan. Dua kategori tipe nilai adalah struct dan enum.

Contoh berikut menunjukkan anggota tipe boolean. Seperti yang Anda lihat, tidak ada referensi eksplisit ke kelas System.ValueType, ini terjadi karena kelas ini diwarisi oleh struct.

namespace System
{
    [ComVisible(true)]
    public struct Boolean : IComparable, IConvertible, IComparable<Boolean>, IEquatable<Boolean>
    {
        public static readonly string TrueString;
        public static readonly string FalseString;
        public static Boolean Parse(string value);
        ...
    }
}

Jenis referensi Di sisi lain, jenis referensi tidak berisi data aktual yang disimpan dalam variabel, tetapi alamat memori dari heap tempat nilai disimpan. Kategori tipe referensi adalah kelas, delegasi, array, dan antarmuka.

Pada waktu proses, ketika variabel tipe referensi dideklarasikan, itu berisi nilai null hingga objek yang telah dibuat menggunakan kata kunci baru ditugaskan padanya.

Contoh berikut menunjukkan anggota Daftar tipe generik.

namespace System.Collections.Generic
{
    [DebuggerDisplay("Count = {Count}")]
    [DebuggerTypeProxy(typeof(Generic.Mscorlib_CollectionDebugView<>))]
    [DefaultMember("Item")]
    public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    {
        ...
        public T this[int index] { get; set; }
        public int Count { get; }
        public int Capacity { get; set; }
        public void Add(T item);
        public void AddRange(IEnumerable<T> collection);
        ...
    }
}

Jika Anda ingin mengetahui alamat memori objek tertentu, class System.Runtime.InteropServices menyediakan cara untuk mengakses objek yang dikelola dari memori yang tidak dikelola. Dalam contoh berikut, kita akan menggunakan metode statis GCHandle.Alloc () untuk mengalokasikan pegangan ke string dan kemudian metode AddrOfPinnedObject untuk mengambil alamatnya.

string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");

Outputnya adalah

Memory address:39723832

Referensi Dokumentasi resmi: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019

Ivan Porta
sumber
-1

Ada banyak detail kecil tentang perbedaan antara tipe nilai dan tipe referensi yang dinyatakan secara eksplisit oleh standar dan beberapa di antaranya tidak mudah dipahami, terutama bagi pemula.

Lihat standar ECMA 33, Common Language Infrastructure (CLI) . CLI juga distandarisasi oleh ISO. Saya akan memberikan referensi tetapi untuk ECMA kita harus mengunduh PDF dan tautan itu tergantung pada nomor versinya. Standar ISO membutuhkan biaya.

Satu perbedaan adalah bahwa tipe nilai dapat dikotakkan tetapi tipe referensi umumnya tidak bisa. Ada pengecualian tetapi cukup teknis.

Jenis nilai tidak boleh memiliki konstruktor atau finalizer instance tanpa parameter dan tidak dapat merujuk ke dirinya sendiri. Merujuk pada dirinya sendiri berarti misalnya jika ada Node yang berjenis nilai maka salah satu anggota Node tidak bisa menjadi Node . Saya rasa ada persyaratan / batasan lain dalam spesifikasi tetapi jika demikian maka mereka tidak dikumpulkan di satu tempat.

pengguna34660
sumber