Sebuah struct, pada intinya, tidak lebih dan tidak kurang dari kumpulan bidang. Dalam .NET, mungkin saja struktur "berpura-pura" menjadi objek, dan untuk setiap jenis struktur .NET secara implisit mendefinisikan tipe objek heap dengan bidang dan metode yang sama yang - menjadi objek heap - akan berperilaku seperti objek . Variabel yang menyimpan referensi ke objek heap semacam itu (struktur "kotak") akan menunjukkan semantik referensi, tetapi variabel yang memegang struct secara langsung hanyalah kumpulan variabel.
Saya pikir banyak kebingungan struct-versus-class berasal dari fakta bahwa struktur memiliki dua kasus penggunaan yang sangat berbeda, yang seharusnya memiliki pedoman desain yang sangat berbeda, tetapi pedoman MS tidak membedakannya. Terkadang ada kebutuhan akan sesuatu yang berperilaku seperti objek; dalam hal ini, pedoman MS cukup masuk akal, meskipun "batas 16 byte" mungkin lebih seperti 24-32. Namun terkadang, yang dibutuhkan adalah agregasi variabel. Sebuah struct yang digunakan untuk tujuan itu seharusnya hanya terdiri dari sekumpulan bidang publik, dan mungkin sebuah Equals
override, ToString
override, danIEquatable(itsType).Equals
penerapan. Struktur yang digunakan sebagai agregasi bidang bukanlah objek, dan tidak boleh berpura-pura menjadi. Dari sudut pandang struktur, arti dari field seharusnya tidak lebih atau kurang dari "hal terakhir yang dituliskan pada field ini". Arti tambahan harus ditentukan oleh kode klien.
Misalnya, jika struct pengumpul variabel memiliki anggota Minimum
dan Maximum
, struct itu sendiri seharusnya tidak menjanjikan hal itu Minimum <= Maximum
. Kode yang menerima struktur seperti parameter harus berperilaku seolah-olah diteruskan secara terpisah Minimum
dan Maximum
nilai. Persyaratan yang Minimum
tidak lebih besar dari Maximum
harus dianggap seperti persyaratan bahwa Minimum
parameter tidak boleh lebih besar dari yang diteruskan secara terpisah Maximum
.
Pola yang berguna untuk dipertimbangkan kadang-kadang adalah membuat ExposedHolder<T>
kelas mendefinisikan sesuatu seperti:
class ExposedHolder<T>
{
public T Value;
ExposedHolder() { }
ExposedHolder(T val) { Value = T; }
}
Jika seseorang memiliki List<ExposedHolder<someStruct>>
, di mana someStruct
struct pengumpul-variabel, ia dapat melakukan hal-hal seperti itu myList[3].Value.someField += 7;
, tetapi memberikan myList[3].Value
ke kode lain akan memberikan isinya Value
daripada memberinya sarana untuk mengubahnya. Sebaliknya, jika seseorang menggunakan a List<someStruct>
, itu akan perlu digunakan var temp=myList[3]; temp.someField += 7; myList[3] = temp;
. Jika seseorang menggunakan tipe kelas yang bisa berubah, mengekspos konten myList[3]
ke kode luar akan memerlukan penyalinan semua bidang ke objek lain. Jika seseorang menggunakan tipe kelas yang tidak bisa diubah, atau struct "object-style", maka perlu untuk membuat sebuah instance baru yang seperti myList[3]
kecuali someField
yang berbeda, dan kemudian menyimpan instance baru itu ke dalam daftar.
Satu catatan tambahan: Jika Anda menyimpan banyak hal yang serupa, mungkin baik untuk menyimpannya dalam susunan struktur yang mungkin bersarang, lebih disukai mencoba untuk menjaga ukuran setiap larik antara 1K dan 64K atau lebih. Array struktur adalah khusus, dalam pengindeksan itu akan menghasilkan referensi langsung ke struktur di dalamnya, sehingga seseorang dapat mengatakan "a [12] .x = 5;". Meskipun seseorang dapat mendefinisikan objek mirip array, C # tidak mengizinkan mereka untuk berbagi sintaks seperti itu dengan array.