Di .NET, ada dua kategori tipe, tipe referensi dan tipe nilai .
Structs adalah tipe nilai dan kelas adalah tipe referensi .
Perbedaan umum adalah bahwa tipe referensi tinggal di heap, dan tipe nilai tinggal inline, yaitu, di mana pun itu variabel Anda atau bidang didefinisikan.
Variabel yang berisi tipe nilai berisi seluruh nilai tipe nilai. Untuk struct, itu berarti bahwa variabel berisi seluruh struct, dengan semua bidangnya.
Variabel yang berisi tipe referensi berisi pointer, atau referensi ke tempat lain di memori di mana nilai aktual berada.
Ini memiliki satu manfaat, untuk mulai dengan:
- tipe nilai selalu mengandung nilai
- tipe referensi dapat berisi referensi - nol , yang berarti bahwa mereka tidak merujuk pada apa pun pada saat ini
Secara internal, tipe referensi diimplementasikan sebagai pointer, dan mengetahui itu, dan mengetahui bagaimana tugas variabel bekerja, ada pola perilaku lainnya:
- menyalin isi variabel tipe nilai ke variabel lain, menyalin seluruh konten ke variabel baru, membuat keduanya berbeda. Dengan kata lain, setelah salinan, perubahan yang satu tidak akan memengaruhi yang lain
- menyalin isi variabel tipe referensi ke variabel lain, menyalin referensi, yang berarti Anda sekarang memiliki dua referensi yang sama di tempat lain penyimpanan data aktual. Dengan kata lain, setelah salinan, mengubah data dalam satu referensi juga akan memengaruhi yang lain, tetapi hanya karena Anda benar-benar hanya melihat data yang sama di kedua tempat
Saat Anda mendeklarasikan variabel atau bidang, inilah perbedaan kedua jenis:
- variabel: tipe nilai tinggal di stack, tipe referensi tinggal di stack sebagai penunjuk ke suatu tempat di memori tumpukan di mana memori yang sebenarnya tinggal (meskipun perhatikan seri artikel Eric Lipperts: The Stack Is an Detail Implementasi .)
- class / struct-field: tipe nilai hidup sepenuhnya di dalam tipe, tipe referensi tinggal di dalam tipe sebagai pointer ke suatu tempat di memori tumpukan di mana memori yang sebenarnya tinggal.
Ringkasan masing-masing:
Kelas Saja:
Hanya Structs:
Kelas dan Struktur:
sumber
c# struct memory overhead
dan menemukan jawaban ini oleh Hans Passant yang mengatakan bahwa tidak, itu juga tidak benar. Jadi apa yang Anda maksud?class
dikelola memori (ditangani oleh pengumpul sampah), sedangkan contohstruct
tidak .Dalam .NET deklarasi struct dan kelas membedakan antara tipe referensi dan tipe nilai.
Ketika Anda melewati jenis referensi hanya ada satu yang benar-benar disimpan. Semua kode yang mengakses instance sedang mengakses yang sama.
Ketika Anda melewati suatu tipe nilai masing-masing adalah salinan. Semua kode bekerja pada salinannya sendiri.
Ini dapat ditunjukkan dengan contoh:
Untuk kelas ini akan berbeda
Kelas bisa berupa apa saja - referensi dapat menunjuk ke nol.
Struct adalah nilai aktual - mereka bisa kosong tetapi tidak pernah nol. Karena alasan ini, struct selalu memiliki konstruktor default tanpa parameter - mereka memerlukan 'nilai awal'.
sumber
Perbedaan antara Structs dan Classes:
sumber
Dari Microsoft Memilih Antara Kelas dan Struktur ...
sumber
Selain semua perbedaan yang dijelaskan dalam jawaban lain:
Jika Anda mencari video yang menjelaskan semua perbedaan, Anda dapat melihat Bagian 29 - C # Tutorial - Perbedaan antara kelas dan struct di C # .
sumber
Contoh kelas disimpan di heap yang dikelola. Semua variabel 'mengandung' instance hanyalah referensi ke instance pada heap. Melewati objek ke metode menghasilkan salinan referensi yang diteruskan, bukan objek itu sendiri.
Struktur (secara teknis, tipe nilai) disimpan di mana pun mereka digunakan, seperti tipe primitif. Konten dapat disalin oleh runtime kapan saja dan tanpa meminta copy-constructor yang disesuaikan. Melewati tipe nilai ke metode melibatkan menyalin seluruh nilai, lagi-lagi tanpa meminta kode yang dapat disesuaikan.
Perbedaannya dibuat lebih baik dengan nama C ++ / CLI: "kelas ref" adalah kelas seperti yang dijelaskan pertama, "kelas nilai" adalah kelas seperti yang dijelaskan kedua. Kata kunci "kelas" dan "struct" seperti yang digunakan oleh C # hanyalah sesuatu yang harus dipelajari.
sumber
sumber
Struktur vs Kelas
Struktur adalah tipe nilai sehingga disimpan di tumpukan, tetapi kelas adalah tipe referensi dan disimpan di heap.
Struktur tidak mendukung warisan, dan polimorfisme, tetapi kelas mendukung keduanya.
Secara default, semua anggota struct adalah publik tetapi anggota kelas secara default bersifat pribadi.
Karena struktur adalah tipe nilai, kami tidak dapat menetapkan null ke objek struct, tetapi itu bukan kasus untuk kelas.
sumber
Untuk menambah jawaban lain, ada satu perbedaan mendasar yang perlu diperhatikan, dan itu adalah bagaimana data disimpan dalam array karena ini dapat memiliki efek besar pada kinerja.
Jadi array struct terlihat seperti ini di memori
[struct][struct][struct][struct][struct][struct][struct][struct]
Sedangkan array kelas terlihat seperti ini
[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]
Dengan array kelas, nilai yang Anda minati tidak disimpan dalam array, tetapi di tempat lain di memori.
Untuk sebagian besar aplikasi perbedaan ini tidak terlalu penting, namun, dalam kode kinerja tinggi ini akan mempengaruhi lokalitas data dalam memori dan memiliki dampak besar pada kinerja cache CPU. Menggunakan kelas ketika Anda bisa / seharusnya menggunakan struct akan secara besar-besaran meningkatkan jumlah cache yang gagal pada CPU.
Hal paling lambat yang dilakukan CPU modern adalah bukan angka-angka, itu mengambil data dari memori, dan hit cache L1 berkali-kali lebih cepat daripada membaca data dari RAM.
Berikut beberapa kode yang dapat Anda uji. Di mesin saya, iterasi melalui array kelas membutuhkan ~ 3x lebih lama dari array struct.
sumber
Hanya untuk membuatnya lengkap, ada perbedaan lain ketika menggunakan
Equals
metode ini, yang diwarisi oleh semua kelas dan struktur.Katakanlah kita memiliki kelas dan struktur:
dan dalam metode Utama, kami memiliki 4 objek.
Kemudian:
Jadi , struktur cocok untuk objek seperti numerik, seperti titik (simpan koordinat x dan y). Dan kelas cocok untuk orang lain. Bahkan jika 2 orang memiliki nama, tinggi, berat yang sama ..., mereka masih 2 orang.
sumber
Nah, untuk permulaan, sebuah struct dilewatkan oleh nilai daripada oleh referensi. Structs baik untuk struktur data yang relatif sederhana, sementara kelas memiliki lebih banyak fleksibilitas dari sudut pandang arsitektur melalui polimorfisme dan pewarisan.
Orang lain mungkin bisa memberi Anda lebih banyak detail daripada saya, tetapi saya menggunakan struct ketika struktur yang saya gunakan sederhana.
sumber
Selain perbedaan dasar dari specifier akses, dan beberapa yang disebutkan di atas saya ingin menambahkan beberapa perbedaan utama termasuk beberapa yang disebutkan di atas dengan sampel kode dengan output, yang akan memberikan ide yang lebih jelas tentang referensi dan nilai
Structs:
Kelas:
Contoh kode
Keluaran
Nilai awal dari Struct Object adalah: 10
Metode Inside Struct Nilai Inside Method dari Struct Object adalah: 20
Setelah nilai panggilan Metode Objek Struct adalah: 10
Nilai awal Obyek Kelas adalah: 10
Metode Inside Class Nilai Inside Method dari Class Object adalah: 20
Nilai panggilan Metode Setelah Kelas Obyek adalah: 20
Di sini Anda dapat dengan jelas melihat perbedaan antara panggilan berdasarkan nilai dan panggilan dengan referensi.
sumber
Acara yang dideklarasikan di kelas memiliki akses + = dan - = mereka secara otomatis dikunci melalui kunci (ini) untuk membuatnya aman (acara statis dikunci pada tipe kelas). Acara yang dideklarasikan dalam struct tidak memiliki akses + = dan - = mereka yang dikunci secara otomatis. Kunci (ini) untuk struct tidak akan berfungsi karena Anda hanya bisa mengunci pada ekspresi tipe referensi.
Membuat instance struct tidak dapat menyebabkan pengumpulan sampah (kecuali jika konstruktor secara langsung atau tidak langsung membuat instance tipe referensi) sedangkan membuat instance tipe referensi dapat menyebabkan pengumpulan sampah.
Sebuah struct selalu memiliki konstruktor default publik bawaan.
Ini berarti bahwa struct selalu instantiable sedangkan kelas mungkin tidak karena semua konstruktornya bisa pribadi.
Str tidak dapat memiliki destruktor. Sebuah destructor hanyalah sebuah override objek. Finalisasi dalam penyamaran, dan struct, sebagai tipe nilai, tidak dikenakan pengumpulan sampah.
Struct secara implisit disegel, kelas tidak.
Sebuah struct tidak bisa abstrak, sebuah kelas bisa.
Sebuah struct tidak dapat memanggil: base () dalam konstruktornya sedangkan kelas tanpa kelas dasar eksplisit dapat.
Sebuah struct tidak dapat memperluas kelas lain, sebuah kelas bisa.
Sebuah struct tidak dapat mendeklarasikan anggota yang dilindungi (misalnya, bidang, tipe bersarang) sebuah kelas bisa.
Sebuah struct tidak dapat mendeklarasikan anggota fungsi abstrak, sebuah kelas abstrak bisa.
Sebuah struct tidak dapat mendeklarasikan anggota fungsi virtual, sebuah kelas dapat.
Sebuah struct tidak dapat mendeklarasikan anggota fungsi yang disegel, sebuah kelas dapat.
Sebuah struct tidak bisa mendeklarasikan override fungsi anggota, sebuah kelas bisa.
Satu-satunya pengecualian untuk aturan ini adalah bahwa struct dapat menimpa metode virtual System.Object, viz, Equals (), dan GetHashCode (), dan ToString ().
sumber
Object
, yang akan menyimpan referensi ke salinan kotak dari struct.Seperti yang disebutkan sebelumnya: Kelas adalah tipe referensi sedangkan Structs adalah tipe nilai dengan semua konsekuensinya.
Sebagai pedoman praktis, Pedoman Desain Kerangka merekomendasikan penggunaan Struct daripada kelas jika:
sumber
Ada satu kasus menarik dari teka-teki "kelas vs struct" - situasi ketika Anda harus mengembalikan beberapa hasil dari metode ini: pilih yang akan digunakan. Jika Anda tahu cerita ValueTuple - Anda tahu bahwa ValueTuple (struct) ditambahkan karena itu harus lebih efektif daripada Tuple (kelas). Tapi apa artinya angka? Dua tes: satu adalah struct / kelas yang memiliki 2 bidang, lainnya dengan struct / kelas yang memiliki 8 bidang (dengan dimensi lebih dari 4 - kelas harus menjadi lebih efektif daripada struct dalam hal kutu prosesor, tetapi tentu saja beban GC juga harus dipertimbangkan ).
PS Tolok ukur lain untuk kasus khusus 'kokoh atau kelas dengan koleksi' ada di sana: https://stackoverflow.com/a/45276657/506147
Tes kode:
sumber
Ini benar, namun juga perhatikan bahwa pada. NET 2 struct mendukung versi Nullable dan C # memasok beberapa gula sintaksis untuk membuatnya lebih mudah digunakan.
sumber
(object)(default(int?)) == null
yang tidak dapat Anda lakukan dengan jenis nilai lain, karena ada lebih dari sekadar gula yang terjadi di sini. Gula hanyaint?
untukNullable<int>
.Setiap variabel atau bidang tipe nilai primitif atau tipe struktur memiliki contoh unik dari tipe itu, termasuk semua bidangnya (publik dan pribadi). Sebaliknya, variabel atau bidang tipe referensi dapat dianggap nol, atau dapat merujuk ke suatu objek, disimpan di tempat lain, di mana sejumlah referensi lain mungkin juga ada. Bidang struct akan disimpan di tempat yang sama dengan variabel atau bidang tipe struktur itu, yang mungkin berada di tumpukan atau mungkin menjadi bagian dari objek tumpukan lain.
Membuat variabel atau bidang tipe nilai primitif akan membuatnya dengan nilai default; membuat variabel atau bidang tipe struktur akan membuat contoh baru, membuat semua bidang di dalamnya secara default. Membuat instance baru dari jenis referensi akan mulai dengan membuat semua bidang di dalamnya secara default, dan kemudian menjalankan kode tambahan opsional tergantung pada jenisnya.
Menyalin satu variabel atau bidang dari tipe primitif ke yang lain akan menyalin nilainya. Menyalin satu variabel atau bidang tipe struktur ke yang lain akan menyalin semua bidang (publik dan pribadi) dari contoh sebelumnya ke contoh terakhir. Menyalin satu variabel atau bidang tipe referensi ke yang lain akan menyebabkan yang terakhir merujuk ke instance yang sama dengan yang sebelumnya (jika ada).
Penting untuk dicatat bahwa dalam beberapa bahasa seperti C ++, perilaku semantik suatu tipe tidak tergantung pada bagaimana ia disimpan, tetapi itu tidak berlaku untuk .NET. Jika suatu tipe mengimplementasikan semantik nilai yang dapat diubah, menyalin satu variabel dari tipe itu ke yang lain menyalin properti dari instance pertama ke yang lain, dirujuk oleh yang kedua, dan menggunakan anggota dari yang kedua untuk bermutasi akan menyebabkan instance kedua tersebut diubah , tapi bukan yang pertama. Jika suatu tipe mengimplementasikan semantik referensi yang dapat berubah, menyalin satu variabel ke variabel lain dan menggunakan anggota yang kedua untuk bermutasi objek akan mempengaruhi objek yang dirujuk oleh variabel pertama; tipe dengan semantik yang tidak berubah tidak memungkinkan mutasi, jadi tidak masalah secara semantik apakah penyalinan membuat instance baru atau membuat referensi lain ke yang pertama.
Di .NET, dimungkinkan untuk tipe nilai untuk mengimplementasikan semantik di atas, asalkan semua bidang mereka dapat melakukan hal yang sama. Namun, tipe referensi hanya dapat menerapkan semantik referensi yang bisa berubah atau semantik yang tidak dapat diubah; tipe nilai dengan bidang tipe referensi yang bisa berubah terbatas baik untuk mengimplementasikan semantik referensi yang dapat diubah atau semantik hibrid yang aneh.
sumber