it-swarm-id.com

Kapan saya harus menggunakan struct, bukan kelas?

MSDN mengatakan bahwa Anda harus menggunakan struct ketika Anda membutuhkan benda ringan. Apakah ada skenario lain ketika struct lebih disukai daripada kelas?

Beberapa orang mungkin lupa bahwa:

  1. structs dapat memiliki metode.
  2. struct tidak dapat diwarisi.

Saya mengerti perbedaan teknis antara struct dan kelas, saya hanya tidak memiliki perasaan yang baik untuk ketika untuk menggunakan sebuah struct.

295
Esteban Araya

MSDN memiliki jawabannya: Memilih Antara Kelas dan Struktur .

Pada dasarnya, halaman itu memberi Anda daftar periksa 4-item dan mengatakan untuk menggunakan kelas kecuali tipe Anda memenuhi semua kriteria.

Jangan mendefinisikan struktur kecuali tipe memiliki semua karakteristik berikut:

  • Secara logis mewakili nilai tunggal, mirip dengan tipe primitif (integer, dobel, dan sebagainya).
  • Ini memiliki ukuran instance lebih kecil dari 16 byte.
  • Itu tidak berubah.
  • Itu tidak harus sering kotak.
293
OwenP

Saya terkejut saya belum membaca jawaban yang sebelumnya, yang saya anggap sebagai aspek paling penting:

Saya menggunakan struct ketika saya ingin jenis tanpa identitas. Misalnya titik 3D:

public struct ThreeDimensionalPoint
{
    public readonly int X, Y, Z;
    public ThreeDimensionalPoint(int x, int y, int z)
    {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }

    public override string ToString()
    {
        return "(X=" + this.X + ", Y=" + this.Y + ", Z=" + this.Z + ")";
    }

    public override int GetHashCode()
    {
        return (this.X + 2) ^ (this.Y + 2) ^ (this.Z + 2);
    }

    public override bool Equals(object obj)
    {
        if (!(obj is ThreeDimensionalPoint))
            return false;
        ThreeDimensionalPoint other = (ThreeDimensionalPoint)obj;
        return this == other;
    }

    public static bool operator ==(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2)
    {
        return p1.X == p2.X && p1.Y == p2.Y && p1.Z == p2.Z;
    }

    public static bool operator !=(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2)
    {
        return !(p1 == p2);
    }
}

Jika Anda memiliki dua contoh struct ini, Anda tidak peduli apakah itu satu atau dua data dalam memori atau dua. Anda hanya peduli dengan nilai yang mereka miliki.

53
Andrei Rînea

Bill Wagner memiliki bab tentang ini dalam bukunya "efektif c #" ( http://www.Amazon.com/Effective-Specific-Ways-Improve-Your/dp/032124566 ). Dia menyimpulkan dengan menggunakan prinsip berikut:

  1. Apakah responsabilitas utama tipe penyimpanan data?
  2. Apakah antarmuka publiknya sepenuhnya ditentukan oleh properti yang mengakses atau memodifikasi anggota datanya?
  3. Apakah Anda yakin tipe Anda tidak akan pernah memiliki subclass?
  4. Apakah Anda yakin jenis Anda tidak akan pernah dirawat secara polimorfik?

Jika Anda menjawab 'ya' untuk semua 4 pertanyaan: gunakan struct. Kalau tidak, gunakan kelas.

27
Bart Gijssens

Gunakan struct ketika Anda ingin semantik tipe nilai bukan tipe referensi. Struct adalah copy-by-value jadi hati-hati!

Lihat juga pertanyaan sebelumnya, mis.

Apa perbedaan antara struct dan kelas di .NET?

15
Simon Steele

Saya akan menggunakan struct ketika:

  1. suatu objek seharusnya hanya dibaca (setiap kali Anda lulus/menetapkan struct itu akan disalin). Hanya baca objek yang bagus untuk pemrosesan multithreaded karena mereka tidak cukup mengunci dalam banyak kasus.

  2. sebuah benda kecil dan berumur pendek. Dalam kasus seperti itu ada kemungkinan besar bahwa objek akan dialokasikan pada tumpukan yang jauh lebih efisien daripada meletakkannya di tumpukan yang dikelola. Terlebih lagi memori yang dialokasikan oleh objek akan dibebaskan segera setelah melampaui ruang lingkupnya. Dengan kata lain itu kurang bekerja untuk Pengumpul Sampah dan memori yang digunakan lebih efisien.

11
Pawel Pabich

Gunakan kelas jika:

  • Identitasnya penting. Struktur disalin secara implisit ketika diteruskan oleh nilai ke dalam metode.
  • Ini akan memiliki jejak memori yang besar.
  • Bidangnya membutuhkan inisialisasi.
  • Anda perlu mewarisi dari kelas dasar.
  • Anda membutuhkan perilaku polimorfik;

Gunakan struktur jika:

  • Ini akan bertindak seperti tipe primitif (int, panjang, byte, dll.).
  • Itu harus memiliki jejak memori kecil.
  • Anda memanggil metode P/Invoke yang membutuhkan struktur untuk diteruskan oleh nilai.
  • Anda perlu mengurangi dampak pengumpulan sampah pada kinerja aplikasi.
  • Bidangnya harus diinisialisasi hanya ke nilai defaultnya. Nilai ini akan nol untuk tipe numerik, false untuk tipe Boolean, dan null untuk tipe referensi.
    • Perhatikan bahwa dalam C # 6.0 struct dapat memiliki konstruktor default yang dapat digunakan untuk menginisialisasi bidang struct ke nilai-nilai tidak cacat.
  • Anda tidak perlu mewarisi dari kelas dasar (selain ValueType, dari mana semua struct mewarisi).
  • Anda tidak perlu perilaku polimorfik.

Saya selalu menggunakan struct ketika saya ingin mengelompokkan beberapa nilai untuk melewatkan sesuatu dari pemanggilan metode, tapi saya tidak perlu menggunakannya untuk apa pun setelah saya membaca nilai-nilai itu. Sama seperti cara untuk menjaga kebersihan. Saya cenderung melihat hal-hal di struct sebagai "membuang" dan hal-hal di kelas sebagai lebih berguna dan "fungsional"

5
Ryan Skarin

Jika suatu entitas akan berubah, pertanyaan apakah akan menggunakan struct atau kelas umumnya akan menjadi salah satu kinerja daripada semantik. Pada sistem 32/64-bit, referensi kelas membutuhkan 4/8 byte untuk disimpan, terlepas dari jumlah informasi di kelas; menyalin referensi kelas akan membutuhkan menyalin 4/8 byte. Di sisi lain, setiap berbeda instance kelas akan memiliki 8/16 byte overhead selain informasi yang dimilikinya dan biaya memori referensi untuk itu. Misalkan seseorang menginginkan array 500 entitas, masing-masing memegang empat bilangan bulat 32-bit. Jika entitas adalah tipe struktur, array akan membutuhkan 8.000 byte terlepas dari apakah semua 500 entitas semuanya identik, semua berbeda, atau di antara keduanya. Jika entitas adalah tipe kelas, array 500 referensi akan mengambil 4.000 byte. Jika semua referensi menunjuk ke objek yang berbeda, objek akan memerlukan tambahan 24 byte masing-masing (12.000 byte untuk semua 500), total 16.000 byte - dua kali biaya penyimpanan dari jenis struct. Di sisi lain, dari kode yang dibuat satu instance objek dan kemudian disalin referensi ke semua 500 array slot, total biaya akan menjadi 24 byte untuk instance itu dan 4.000 untuk array - total 4.024 byte. Penghematan besar. Beberapa situasi akan berhasil serta yang terakhir, tetapi dalam beberapa kasus mungkin untuk menyalin beberapa referensi ke slot array yang cukup untuk membuat berbagi seperti itu bermanfaat.

Jika entitas seharusnya bisa berubah, pertanyaan apakah menggunakan kelas atau struct dalam beberapa hal lebih mudah. Asumsikan "Benda" adalah suatu struct atau kelas yang memiliki bidang bilangan bulat yang disebut x, dan seseorang melakukan kode berikut:

 Hal t1, t2; 
 ... 
 T2 = t1; 
 T2.x = 5; 

Apakah orang ingin pernyataan yang terakhir mempengaruhi t1.x?

Jika Benda adalah tipe kelas, t1 dan t2 akan setara, artinya t1.x dan t2.x juga akan setara. Dengan demikian, pernyataan kedua akan mempengaruhi t1.x. Jika Benda adalah tipe struktur, t1 dan t2 akan menjadi instance yang berbeda, artinya t1.x dan t2.x akan merujuk ke bilangan bulat yang berbeda. Dengan demikian, pernyataan kedua tidak akan mempengaruhi t1.x.

Struktur yang dapat berubah dan kelas yang dapat berubah memiliki perilaku yang berbeda secara mendasar, meskipun .net memiliki beberapa kebiasaan dalam penanganan mutasi struktural. Jika seseorang menginginkan perilaku tipe-nilai (artinya "t2 = t1" akan menyalin data dari t1 ke t2 sambil meninggalkan t1 dan t2 sebagai contoh berbeda), dan jika seseorang dapat hidup dengan quirks dalam penanganan jenis nilai .net menggunakan, sebuah struktur. Jika seseorang menginginkan semantik tipe-nilai tetapi kebiasaan .net akan menyebabkan rusaknya semantik tipe-nilai dalam aplikasi seseorang, gunakan kelas dan bergumam.

4
supercat

Selain itu jawaban yang sangat baik di atas:

Struktur adalah tipe nilai.

Mereka tidak pernah dapat diatur ke Tidak Ada.

Mengatur struktur = Tidak ada, akan mengatur semua jenis nilainya ke nilai standarnya.

3

ketika Anda tidak benar-benar membutuhkan perilaku, tetapi Anda membutuhkan lebih banyak struktur daripada array atau kamus sederhana.

Tindak lanjut Ini adalah bagaimana saya berpikir tentang struct secara umum. Saya tahu mereka dapat memiliki metode, tetapi saya suka menjaga perbedaan mental secara keseluruhan.

2
Jim Deville

Seperti kata @Simon, struct menyediakan semantik "nilai-tipe" jadi jika Anda memerlukan perilaku yang mirip dengan tipe data bawaan, gunakan struct. Karena struct dilewatkan melalui salinan, Anda ingin memastikan ukurannya kecil, sekitar 16 byte.

2
Scott Dorman

Struct berada di Stack bukan Heap jadi oleh karena itu mereka thread aman, dan harus digunakan ketika menerapkan pola objek transfer, Anda tidak pernah ingin menggunakan objek di Heap mereka volatile, Anda ingin dalam hal ini menggunakan Call Stack, ini adalah kasus dasar untuk menggunakan struct saya terkejut dengan semua jalan keluar jawabannya di sini,

1
Jack

Hmm ...

Saya tidak akan menggunakan pengumpulan sampah sebagai argumen untuk/menentang penggunaan struct vs kelas. Tumpukan terkelola bekerja sangat mirip tumpukan - membuat objek hanya menempatkannya di atas tumpukan, yang hampir secepat mengalokasikan pada tumpukan. Selain itu, jika suatu objek berumur pendek dan tidak bertahan dari siklus GC, deallokasi bebas karena GC hanya bekerja dengan memori yang masih dapat diakses. (Cari MSDN, ada serangkaian artikel tentang manajemen memori .NET, saya terlalu malas untuk menggali untuk mereka).

Sebagian besar waktu saya menggunakan struct, saya akhirnya menendang diri saya untuk melakukannya, karena saya kemudian menemukan bahwa memiliki referensi semantik akan membuat segalanya lebih sederhana.

Bagaimanapun, keempat poin dalam artikel MSDN yang diposting di atas tampaknya merupakan pedoman yang baik.

1
KG