Mengapa menggunakan kelas parsial?

72

Dalam pemahaman saya, partialkata kunci tidak melakukan apa pun kecuali memungkinkan kelas untuk dibagi antara beberapa file sumber. Apakah ada alasan untuk melakukan ini selain untuk organisasi kode? Saya pernah melihatnya digunakan untuk itu di kelas UI yang dihasilkan.

Tampaknya alasan yang buruk untuk membuat keseluruhan kata kunci. Jika sebuah kelas cukup besar untuk membutuhkan banyak file, itu mungkin terlalu banyak. Saya berpikir bahwa mungkin Anda bisa menggunakannya untuk mendefinisikan sebagian kelas untuk programmer lain di suatu tempat untuk menyelesaikan, tetapi akan lebih baik untuk membuat kelas abstrak.

Michael K.
sumber
10
Ini juga bukan "keseluruhan kata kunci". Itu kata kunci kontekstual . partialhanya berarti sesuatu ketika datang sebelumnya class. Anda dapat menggunakannya sebagai nama pengenal di bagian lain kode, dll.
Dean Harding
4
Jika Anda menggunakannya, dan itu bukan untuk kode yang dihasilkan, saya benci Anda. Bukan Anda secara pribadi, tetapi Anda umumnya. Saya benci memburu kode melalui kelas parsial.
Steven Evers
3
Tidak sulit untuk "memburu kode", semua metode kelas masih muncul di drop down di VS, terlepas dari bagian mana dari parsial yang Anda lihat. Navigasi kode lain juga berfungsi dengan baik (baik navigasi gaya "pintar" R # atau shift-ctrl-f lama yang bagus
Steve
2
Ini adalah kesalahpahaman bahwa kelas parsial harus dalam file terpisah.
Bart

Jawaban:

110

Ini sangat berguna dalam setiap skenario di mana satu bagian kelas dihasilkan oleh beberapa alat kustom karena memungkinkan Anda untuk menambahkan logika khusus ke kode yang dihasilkan tanpa mewarisi kelas yang dihasilkan. Btw. ada juga metode parsial untuk alasan yang sama.

Ini bukan hanya tentang UI tetapi juga teknologi lain seperti Linq-To-Sql atau Entity Framework menggunakan ini cukup banyak.

Ladislav Mrnka
sumber
44
Selain itu, ini memungkinkan Anda menjaga kode Anda di bawah kontrol versi sambil meninggalkan kode yang dihasilkan di luar kontrol versi.
Frank Shearar
3
Poin bagus, saya tidak pernah memikirkan itu. Saya hanya melihatnya dilecehkan dalam praktek. Sebuah cara bagi pemrogram (buruk) untuk menjaga ukuran file dapat dikelola.
Martin Wickman
1
Contoh terbaik yang saya gunakan adalah: a) untuk Linq ke konteks data SQL di mana Anda ingin memperluas kelas; b) untuk memperpanjang kelas yang lulus dari layanan web. Dalam kedua kasus ini adalah penyalahgunaan atau sarana untuk menjaga ukuran file dapat dikelola ... Saya akan sangat tidak senang melihatnya digunakan dengan cara itu (dan akan mengambil langkah-langkah ...)
Murph
3
Kelas-kelas WinForm menggunakannya untuk menyembunyikan semua kontrol pembuatan kode perancang (terutama penting karena perancang suka secara acak menyusun ulang semua kode yang dihasilkannya sehingga menghasilkan kekacauan besar ketika diff / menyalahkan), dan jika Anda bekerja dengan XML, alat XSD dapat buat kelas parsial dari file skema lagi memungkinkan Anda untuk memisahkan kode Anda dari jenis yang dihasilkan secara otomatis.
Dan Neely
2
@ MartinWickman belum tentu jelek. Ini adalah titik awal yang baik untuk refactoring objek Dewa dalam kode legacy. Cobalah untuk menghapus lansekap dengan memecah kelas-kelas besar menjadi file terpisah terlebih dahulu. (Saya tahu komentar Anda sudah sangat tua)
Konrad Morawski
26

Seperti yang Anda katakan, ini sering digunakan untuk memisahkan kode yang dihasilkan. Seringkali tidak ada hubungannya dengan ukuran kelas / file.

Manfaat memisahkan kode yang dihasilkan adalah gaya. Kode yang dihasilkan bisa sangat jelek dan tidak dapat dibaca dan akan gagal banyak standar pengkodean (dan cek StyleCop), tapi tidak apa-apa, tidak ada yang harus membacanya atau memeliharanya secara langsung. Jadi, jika Anda "menyembunyikan" di file lain, Anda dapat fokus untuk memastikan bahwa seluruh kelas sudah sesuai standar, melewati cek StyleCop dan sebagainya.

Area lain di mana saya menggunakannya adalah di mana sebuah kelas mengimplementasikan beberapa antarmuka, bisa sangat bagus untuk memisahkan implementasi ke dalam file terpisah, meskipun ini lebih merupakan masalah preferensi pribadi, saya belum pernah melihat standar pengkodean memerlukan ( atau mencegah) ini.

Steve
sumber
9
Saya tidak pernah berpikir untuk menggunakan parsial kelas untuk memisahkan implementasi antarmuka, itu ide yang bagus.
Mark Booth
Ini lebih dari sekedar gaya. Pengembang pembuat kode harus melewati rintangan untuk memungkinkan Anda mengedit kode dalam file yang dikelola oleh generator, dan bahkan kemudian itu akan menjadi masalah. Manfaat # 1, bagi saya, adalah memberi Anda tempat untuk menulis kode yang generator tidak akan menyentuh. Ini adalah manfaat yang sangat nyata.
Daniel
19

Salah satu pengembang tempat saya bekerja muncul untuk penggunaan yang cukup baik bagi mereka beberapa minggu yang lalu dalam refactoring kelas Dewa besar yang telah berputar di luar kendali dan memiliki banyak metode publik: dengan memisahkan fungsi logis dari setiap bit kelas menjadi kelas parsial yang terpisah Anda dapat secara fisik memisahkan kelas menjadi unit yang lebih atom yang seharusnya menjadi kelas tanpa melanggar fungsi yang ada, memungkinkan Anda untuk melihat apa yang umum dan apa yang tidak. Dengan ini sebagai tahap pertama Anda kemudian dapat dengan lebih mudah memecah parsial ke dalam kelas independen mereka sendiri dan mengimplementasikannya di seluruh basis kode. Saya pikir ini ide yang bagus.

Namun, secara umum saya berpikir bahwa mereka hanya boleh digunakan untuk menambah kelas yang dihasilkan mesin saat menulis kode baru.


sumber
1
Saya bisa melihat bagaimana itu bisa berguna. Apakah itu pembenaran untuk itu dalam bahasa atau tidak ... Saya tidak tahu. Mesin menghasilkan kode cerita lain.
Michael K
2
Ya, itu bukan pembenaran untuk menggunakan bahasa itu, tapi ini cara yang menarik untuk menggunakannya.
18

Saya dapat memikirkan beberapa skenario yang bermanfaat di mana sebagian masuk akal, sebagian besar dari mereka saya gunakan sendiri dalam proyek saya:

  • Untuk memisahkan Alat / IDE / Desainer kode yang dihasilkan dari kode yang Anda pertahankan. Contoh yang baik adalah Form.Designer.csfile yang berisi kode yang dihasilkan perancang untuk windows membentuk aplikasi. Banyak format .NET lainnya juga memiliki beberapa kode yang dihasilkan alat, yang dapat berpotensi dibuat ulang ketika Anda membangun proyek Anda, dan dengan demikian semua perubahan kustom Anda akan terhapus. Pemisahan ini akan membantu Anda menjaga kode Anda dan perubahan aman dari modifikasi otomatis tersebut.

  • Ketika Anda mengimplementasikan beberapa antarmuka dengan banyak kode dalam implementasi. Saya cenderung menggunakan file parsial terpisah untuk setiap antarmuka seperti, penamaan itu seperti ini: {Class}.{Interface}.cs. Sangat mudah bagi saya untuk melihat di IDE yang {Class}mengimplementasikan antarmuka dan bagaimana.

  • Ketika kelas harus berisi satu atau lebih kelas bersarang , terutama dengan kode yang cukup di dalamnya untuk dimasukkan ke file yang terpisah. Saya akan tetap berpegang pada pola di atas dan menggunakan {Class}.{NestedClass}.cskonvensi penamaan untuk setiap kelas bersarang. Latihan serupa sudah disebutkan oleh jawaban Virtlink .

  • Ketika saya menulis statickelas yang akan menampung metode ekstensi . Akan sering terjadi untuk memberikan logika metode ekstensi yang sama ke kelas atau antarmuka yang sama - seperti misalnya Reversepada koleksi generik dan non-generik. Saya akan meletakkan semua metode ekstensi untuk satu kelas atau antarmuka dalam parsial terpisah dari kelas statis. Sebagai contoh, saya memiliki semua metode ekstensi untuk IListantarmuka di satu tempat, dan metode yang sama untuk IList<T>di file lain. Pendekatan lain adalah menempatkan metode yang sama (semua kelebihannya) di parsial yang sama, dengan semua kelas yang mungkin untuk thisparameter - seperti memiliki semuaReverseimplementasi dalam satu file. Tergantung mana yang akan membenarkan pemisahan dalam hal volume kode, atau beberapa konvensi internal yang Anda atau organisasi Anda mungkin tempati.

  • Saya tidak menggunakan ini, tetapi saya telah melihat beberapa orang C / C ++ menyukai pendekatan yang akan saya jelaskan di sini: membuat parsial untuk kelas dengan metode parsial saja. Ini menyerupai cara C / C ++ untuk mendefinisikan antarmuka dan memisahkan deklarasi metode dari implementasi.

  • Pemisahan dengan keprihatinan murni logis . Jika Anda kebetulan bekerja dengan kelas besar yang menggabungkan lebih dari satu set logis operasi itu sendiri, maka Anda dapat memisahkan masing-masing kode yang terkait secara logis menjadi parsial yang terpisah. Biasanya keberadaan kelas-kelas semacam itu bertentangan dengan prinsip pemisahan perhatian , tetapi sering kali diamati kasus nyata, khususnya untuk basis kode yang lebih lama. Rekan pengguna Steve Evers telah menyebut mereka dalam menjawab pertanyaan ini , merujuk pada mereka dengan nama benda dewa. Saya pribadi menggunakan pendekatan kelas parsial untuk membagi kode sebelum refactoring file yang sangat besar tersebut terjadi, untuk memudahkan pekerjaan saya dan membuat refactoring lebih transparan. Ini juga akan mengurangi konflik yang berpotensi menyebabkan ketika sistem versi seperti SVN terlibat.

Ivaylo Slavov
sumber
14

Saya belum melihatnya disebutkan oleh siapa pun: Saya menggunakan partialuntuk menempatkan kelas bersarang di file mereka sendiri.

Semua file kode saya hanya berisi satu kelas, struct, antarmuka atau enum. Itu membuatnya jauh lebih mudah untuk menemukan definisi untuk suatu objek ketika nama file menunjukkan nama dari hal yang Anda cari. Dan karena Visual Studio mencoba untuk mencocokkan folder proyek dengan ruang nama, nama file harus sesuai dengan kelas.

Ini juga berarti bahwa kelas NestedClassbersarang di dalam MyClassakan memiliki file itu sendiri dalam proyek-proyek saya: MyClass.NestedClass.cs.

partial class MyClass
{
    private class NestedClass
    {
        // ...
    }
}
Daniel AA Pelsmaeker
sumber
1
Saya bertanya-tanya mengapa seseorang akan memilih jawaban ini. Praktik yang disebutkan itu bukan anti-pola, juga tidak akan menyebabkan masalah yang saya tahu.
Ivaylo Slavov
1
Ini juga mengatasi masalah menjaga file kelas kecil (dalam hal baris kode) sementara masih memungkinkan enkapsulasi kode yang tepat yang termasuk dalam kelas dalam.
redcalx
10

Dengan pengecualian menggunakan kode yang dihasilkan, saya hanya pernah melihat mereka digunakan dalam upaya untuk menutupi objek dewa . Mencoba untuk memahami basis kode baru atau menavigasi melalui beberapa file sumber, yang merupakan objek yang sama, sangat mengganggu.

Jadi ketika Anda bertanya Why use partial classes?saya jawab: kecuali Anda menggunakan kode yang dibuat, jangan.

Steven Evers
sumber
+1. Ini adalah pertama kalinya saya melihat objek jenis ini disebut nama (objek dewa) dan bahkan resmi. Tidak ada kata terlambat untuk mempelajari sesuatu yang baru.
Ivaylo Slavov
6

Organisasi kode adalah satu-satunya alasan, tetapi tampaknya lebih dalam dari pada awalnya. Jika Anda memiliki kelas parsial tempat bagian dihasilkan, Anda dapat dengan mudah:

  • Regenerasi kode tanpa harus mendeteksi perubahan manual di kelas yang Anda tulis (sehingga Anda tidak menimpa bagian-bagian itu).
  • Kecualikan kelas parsial yang dihasilkan dari cakupan uji, kontrol sumber, metrik, dll.
  • Gunakan kode yang dihasilkan tanpa memaksa Anda untuk mendasarkan strategi pewarisan di sekitarnya (Anda masih dapat mewarisi dari kelas lain).
Deckard
sumber
1

Ada juga beberapa tempat di mana kelas yang dihasilkan / tersirat dinyatakan parsial sehingga jika Dev perlu memperluas mereka mereka memiliki akses penuh tanpa harus mengacaukan tentang mewarisi dan menimpa seluruh tempat. Lihatlah kelas yang dihasilkan di area temp asp.net setelah Anda menjalankan situs webforms untuk pertama kalinya di bawah IIS jika Anda ingin mencoba menangkap beberapa contoh.

Tagihan
sumber
1

Saya bisa memikirkan penggunaan kotor untuk mereka.

Misalkan Anda memiliki beberapa kelas yang membutuhkan fungsionalitas umum, tetapi Anda tidak ingin menyuntikkan fungsionalitas itu ke rantai pewarisan di atasnya. Atau, Anda memiliki serangkaian kelas yang menggunakan kelas pembantu umum.

Pada dasarnya Anda ingin melakukan multiple inheritance tetapi C # no likey. Jadi yang Anda lakukan adalah menggunakan parsial untuk membuat apa yang pada dasarnya adalah #sertakan dalam C / C ++;

Masukkan semua fungsi ke dalam kelas, atau gunakan kelas helper. Kemudian salin helper X kali dan beri nama parsial kelas A, B, C. dan berikan sebagian pada kelas A, B, C Anda.

Penafian: Ya, ini jahat. Jangan pernah melakukannya - terutama jika itu akan membuat orang lain marah pada Anda.

Menandai
sumber
Mixin. Ini dapat dikombinasikan dengan T4 untuk menghindari penyalinan manual ...
Peter Taylor
Seperti disebutkan, ini sangat mirip dengan mixin. Namun, Anda mendekati konsep yang dikenal sebagai "sifat" dan mereka akan dengan aman menangani apa yang Anda coba capai. Saya memiliki deskripsi bahasa-agnostik di publius-ovidius.livejournal.com/314737.html Saya telah mencari implementasi bersih untuk C #, tetapi belum melihat satu pun.
Ovid