Metode dapat dibuat statis, tetapi haruskah itu?

366

Resharper suka menunjukkan beberapa fungsi per halaman asp.net yang bisa dibuat statis. Apakah itu membantu saya jika saya membuatnya statis? Haruskah saya membuatnya statis dan memindahkannya ke kelas utilitas?

dlamblin
sumber
20
Bukankah Resharper benar-benar meneriakkan "kohesi rendah, kohesi rendah"? sekarang saatnya untuk melihat apakah metode tersebut benar-benar milik kelas itu.
PK

Jawaban:

245

Metode statis versus metode Instance
10.2.5 Anggota statis dan instan dari Spesifikasi Bahasa C # menjelaskan perbedaannya. Secara umum, metode statis dapat memberikan peningkatan kinerja yang sangat kecil dibandingkan metode contoh, tetapi hanya dalam situasi yang agak ekstrem (lihat jawaban ini untuk detail lebih lanjut tentang itu).

Aturan CA1822 dalam status FxCop atau Analisis Kode:

"Setelah [menandai anggota sebagai statis], kompiler akan memancarkan situs panggilan non-virtual kepada anggota ini yang akan mencegah pemeriksaan saat runtime untuk setiap panggilan yang memastikan penunjuk objek saat ini adalah nol, ini dapat menghasilkan peningkatan kinerja yang terukur untuk kode yang sensitif terhadap kinerja. Dalam beberapa kasus, kegagalan untuk mengakses instance objek saat ini merupakan masalah kebenaran. "

Kelas Utilitas
Anda seharusnya tidak memindahkan mereka ke kelas utilitas kecuali jika hal itu masuk akal dalam desain Anda. Jika metode statis berhubungan dengan tipe tertentu, seperti ToRadians(double degrees)metode yang berhubungan dengan kelas yang mewakili sudut, masuk akal jika metode itu ada sebagai anggota statis dari tipe itu (catatan, ini adalah contoh berbelit-belit untuk keperluan demonstrasi).

Jeff Yates
sumber
2
> kompiler akan memancarkan situs panggilan non-virtual kepada anggota ini. Sebenarnya itu adalah "kompilator dapat memancarkan ...". Saya ingat sesuatu tentang kompiler C # menggunakan callvirt bukannya panggilan untuk mengatasi beberapa bug potensial.
Jonathan Allen
24
Saya memotong dan menempelkannya langsung dari FxCop 1.36. Jika FxCop salah, cukup adil.
Jeff Yates
5
@ Maxim Tidak yakin saya menghargai pernyataan "omong kosong"; cara yang cukup kasar untuk mendekati orang asing. Namun, titik yang mendasarinya valid; Saya telah memperbarui beberapa hal (9 tahun yang lalu, jadi saya tidak ingat dasar klaim asli saya).
Jeff Yates
10
@ Maxim Poin Anda tidak valid. Saya meyakinkan Anda bahwa saya tidak memiliki peringkat yang baik 9 tahun yang lalu. Saya menghargai komentar yang menunjukkan kesalahan (atau pengeditan yang memperbaikinya), tetapi jangan kasar atau menaruh harapan yang tidak masuk akal pada orang lain. Jangan menyebut sesuatu "omong kosong"; itu menyiratkan niat untuk menipu daripada jujur ​​pada kesalahan kebaikan atau ketidaktahuan. Ini tidak sopan. Saya menyumbangkan waktu saya untuk membantu di sini dan itu benar-benar terasa sia-sia ketika diperlakukan dengan tidak hormat. Jangan beri tahu saya apa yang harus disinggung - itu pilihan saya, bukan pilihan Anda. Pelajari cara menyampaikan maksud Anda dengan rasa hormat dan integritas. Terima kasih.
Jeff Yates
2
@ Maxim Sementara delegasi tidak disimpan di samping setiap instance, setiap instance dari kelas stateless memang menempati beberapa memori di heap, yang merupakan overhead yang tidak berguna. Biasanya layanan instantiating bukan jalan panas dalam aplikasi, tetapi jika aplikasi Anda akhirnya membangun banyak objek ini akan membangun tekanan GC yang dapat dihindari dengan hanya menggunakan metode statis. Klaim awal OP, bahwa dalam situasi ekstrem, metode statis memberikan manfaat kinerja dibandingkan instance stateless, bernuansa dan valid secara tepat.
Asad Saeeduddin
259

Kinerja, polusi namespace dll semua sekunder dalam pandangan saya. Tanyakan pada diri sendiri apa yang logis. Apakah metode ini beroperasi secara logis pada instance dari tipe, atau apakah itu terkait dengan tipe itu sendiri? Jika yang terakhir, buatlah metode statis. Hanya pindahkan ke kelas utilitas jika itu terkait dengan jenis yang tidak di bawah kendali Anda.

Kadang-kadang ada metode yang logis bertindak atas sebuah contoh tapi tidak terjadi untuk menggunakan negara contoh ini belum . Misalnya, jika Anda sedang membangun sistem file dan Anda akan mendapat konsep direktori, tetapi Anda belum mengimplementasikannya, Anda bisa menulis properti yang mengembalikan jenis objek sistem file, dan itu akan selalu hanya "file" - tetapi secara logis terkait dengan instance, dan karenanya harus menjadi metode instance. Ini juga penting jika Anda ingin membuat metode virtual - implementasi khusus Anda mungkin tidak memerlukan keadaan, tetapi kelas turunan mungkin. (Misalnya, menanyakan koleksi apakah hanya baca atau tidak - Anda mungkin belum menerapkan bentuk baca-saja dari koleksi itu, tetapi jelas merupakan properti dari koleksi itu sendiri, bukan jenisnya.)

Jon Skeet
sumber
1
Saya akan berpikir linter yang baik harus memiliki opsi untuk membatasi pesan ke metode non-virtual, karena akan sangat umum bagi metode kelas dasar untuk melakukan apa pun yang praktis. Mengganti metode biasanya akan melakukan sesuatu, tetapi tidak selalu. Kadang-kadang berguna untuk memiliki kelas untuk sesuatu seperti iEnumerable kosong, yang metodenya pada dasarnya mengabaikan instance, tetapi ketika instance diperlukan untuk memilih metode yang tepat untuk digunakan.
supercat
2
"Kadang-kadang ada metode yang secara logis bertindak pada sebuah instance tetapi belum pernah menggunakan keadaan instance itu. Misalnya," Saya menikmati penggunaan Anda "misalnya" dalam contoh ini.
PaulBinder
56

Menandai metode seperti di staticdalam kelas membuatnya jelas bahwa itu tidak menggunakan anggota instance, yang dapat membantu untuk mengetahui kapan membaca kode.

Anda tidak perlu harus memindahkannya ke kelas lain kecuali itu dimaksudkan untuk dibagikan oleh kelas lain yang hanya terkait erat, konsep-bijaksana.

Mark Cidade
sumber
22

Saya yakin ini tidak terjadi dalam kasus Anda, tetapi satu "bau busuk" yang saya lihat dalam beberapa kode yang harus saya derita dengan mempertahankan menggunakan banyak metode statis.

Sayangnya, itu adalah metode statis yang mengasumsikan keadaan aplikasi tertentu. (mengapa yakin, kami hanya akan memiliki satu pengguna per aplikasi! Mengapa tidak memiliki kelas Pengguna melacaknya dalam variabel statis?) Mereka adalah cara termuliakan untuk mengakses variabel global. Mereka juga memiliki konstruktor statis (!), Yang hampir selalu merupakan ide yang buruk. (Saya tahu ada beberapa pengecualian yang masuk akal).

Namun, metode statis cukup berguna ketika mereka memfaktorkan domain-logika yang tidak benar-benar bergantung pada keadaan instance objek. Mereka dapat membuat kode Anda lebih mudah dibaca.

Pastikan Anda meletakkannya di tempat yang tepat. Apakah metode statis memanipulasi keadaan internal objek lain secara intrusi? Bisakah kasus yang baik dibuat bahwa perilaku mereka milik salah satu kelas itu? Jika Anda tidak memisahkan masalah dengan benar, Anda mungkin akan mengalami sakit kepala nanti.

Jason True
sumber
4
Masalah Anda dengan bidang / properti statis, bukan metode statis.
Asad Saeeduddin
10

Ini menarik dibaca:

http://thecuttingledge.com/?p=57

ReSharper sebenarnya tidak menyarankan Anda membuat metode Anda statis. Anda harus bertanya pada diri sendiri mengapa metode itu ada di kelas itu, berlawanan dengan, katakanlah, salah satu kelas yang muncul di tanda tangannya ...

tetapi di sini adalah apa yang dikatakan oleh resharper documentaion: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static

piyama
sumber
2
Saya pikir poin ini diremehkan. Apa alat ini benar-benar memberitahu Anda adalah bahwa metode ini hanya beroperasi pada beberapa anggota kelas lain. Jika itu adalah semacam perintah (atau "use case" atau "berinteraksi") objek, siapa yang bertanggung jawab untuk memanipulasi objek lain, itu bagus. Namun, jika itu hanya memanipulasi satu kelas lain yang terdengar sangat mirip dengan Fitur Envy .
Greg
9

Hanya dengan menambahkan jawaban @Jason True , penting untuk menyadari bahwa hanya menempatkan 'statis' pada suatu metode tidak menjamin bahwa metode tersebut akan 'murni'. Ini akan stateless berkenaan dengan kelas di mana ia dideklarasikan, tetapi mungkin juga mengakses objek 'statis' lainnya yang memiliki status (konfigurasi aplikasi dll.), Ini mungkin tidak selalu menjadi hal yang buruk, tetapi salah satu alasan yang Saya pribadi cenderung lebih suka metode statis ketika saya bisa adalah bahwa jika mereka murni, Anda dapat menguji dan bernalar tentang mereka secara terpisah, tanpa harus khawatir tentang keadaan sekitarnya.

Benjol
sumber
6

Anda harus melakukan apa yang paling mudah dibaca dan intuitif dalam skenario yang diberikan.

Argumen kinerja bukanlah argumen yang bagus kecuali dalam situasi paling ekstrem karena satu-satunya hal yang benar-benar terjadi adalah bahwa satu parameter tambahan ( this) dimasukkan ke stack sebagai metode contoh.

Eric Schoonover
sumber
6

Untuk logika kompleks dalam sebuah kelas, saya telah menemukan metode statis privat berguna dalam menciptakan logika terisolasi, di mana input instance didefinisikan dengan jelas dalam metode signature dan tidak ada contoh efek samping yang dapat terjadi. Semua output harus melalui nilai balik atau parameter keluar / ref. Memecah logika kompleks menjadi blok kode efek samping bebas dapat meningkatkan keterbacaan kode dan kepercayaan tim pengembangan di dalamnya.

Di sisi lain dapat menyebabkan kelas tercemar oleh proliferasi metode utilitas. Seperti biasa, penamaan yang logis, dokumentasi, dan aplikasi yang konsisten dari konvensi pengkodean tim dapat mengatasi hal ini.

G-Wiz
sumber
5

ReSharper tidak memeriksa logikanya. Hanya memeriksa apakah metode ini menggunakan anggota contoh. Jika metode ini pribadi dan hanya dipanggil oleh (mungkin hanya satu) metode instance ini adalah tanda untuk membiarkannya metode instance.

brgerner
sumber
3

Jika fungsi dibagikan di banyak halaman, Anda juga bisa menempatkannya di kelas halaman dasar, dan kemudian memiliki semua halaman asp.net menggunakan fungsi yang diwarisi darinya (dan fungsinya juga masih bisa statis).

Mun
sumber
3

Membuat metode statis berarti Anda dapat memanggil metode dari luar kelas tanpa terlebih dahulu membuat instance dari kelas itu. Ini membantu saat bekerja dengan objek atau add-on vendor pihak ketiga. Bayangkan jika Anda harus terlebih dahulu membuat objek Konsol "con" sebelum memanggil con.Writeline ();

Austin
sumber
Java meminta Anda membuat instance pabrik untuk membuat objek Konsol sebelum memanggil con.Writeline ().
ScottMichaud
2

Ini membantu untuk mengendalikan polusi namespace.

Josh
sumber
8
Bagaimana membuat metode statis membantu menghindari polusi namespace?
lockstock
1
Dari pengalaman, dengan mengelompokkan metode ke dalam kelas dengan metode statis, Anda menghindari pengalaman harus mengawali semua "tas jinjing" dari fungsi longgar yang mungkin bertentangan dengan pustaka lain atau fungsi bawaan. Dengan metode statis, mereka secara efektif diberi namespace di bawah Classname, mis. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi
0

Just my tuppence: Menambahkan semua metode statis bersama ke kelas utilitas memungkinkan Anda untuk menambahkan

using static className; 

untuk pernyataan Anda menggunakan, yang membuat kode lebih cepat untuk mengetik dan lebih mudah dibaca. Sebagai contoh, saya memiliki sejumlah besar apa yang akan disebut "variabel global" dalam beberapa kode yang saya warisi. Daripada membuat variabel global dalam kelas yang merupakan kelas instan, saya mengatur semuanya sebagai properti statis dari kelas global. Itu melakukan pekerjaan, jika berantakan, dan saya bisa mereferensikan properti dengan nama karena saya memiliki namespace statis yang sudah direferensikan.

Saya tidak tahu apakah ini praktik yang baik atau tidak. Saya harus belajar banyak tentang C # 4/5 dan begitu banyak kode warisan untuk refactor sehingga saya hanya mencoba untuk membiarkan tips Roselyn membimbing saya.

Joey

Joseph Morgan
sumber
0

Saya harap, Anda sudah memahami perbedaan antara metode statis dan contoh. Juga, bisa ada jawaban panjang dan pendek. Jawaban panjang sudah disediakan oleh orang lain.

Jawaban singkat saya: Ya, Anda dapat mengubahnya menjadi metode statis jika Resharper menyarankan. Tidak ada salahnya melakukannya. Alih-alih, dengan membuat metode ini statis, Anda sebenarnya menjaga metode tersebut sehingga, jika tidak perlu Anda tidak memasukkan anggota instance ke metode itu. Dengan cara itu, Anda dapat mencapai prinsip OOP " Minimalkan aksesibilitas kelas dan anggota ".

Ketika ReSharper menyarankan bahwa metode instance dapat dikonversi ke metode statis, itu sebenarnya memberitahu Anda, "Kenapa ... metode ini duduk di kelas ini karena tidak benar-benar menggunakan salah satu dari keadaannya?" Jadi, ini memberi Anda makanan untuk dipikirkan. Kemudian, Andalah yang dapat menyadari perlunya memindahkan metode itu ke kelas utilitas statis atau tidak. Menurut prinsip-prinsip SOLID, sebuah kelas seharusnya hanya memiliki satu tanggung jawab inti. Jadi, Anda bisa melakukan pembersihan kelas yang lebih baik dengan cara itu. Terkadang, Anda memang membutuhkan beberapa metode pembantu bahkan di kelas instan Anda. Jika itu masalahnya, Anda dapat menyimpannya dalam #region helper.

Emran Hussain
sumber