Keuntungan Menggunakan Metode Statis Privat

209

Saat membuat kelas yang memiliki metode privat internal, biasanya untuk mengurangi duplikasi kode, yang tidak memerlukan penggunaan bidang instance apa pun, adakah keuntungan kinerja atau memori untuk mendeklarasikan metode sebagai statis?

Contoh:

foreach (XmlElement element in xmlDoc.DocumentElement.SelectNodes("sample"))
{
    string first = GetInnerXml(element, ".//first");
    string second = GetInnerXml(element, ".//second");
    string third = GetInnerXml(element, ".//third");
}

...

private static string GetInnerXml(XmlElement element, string nodeName)
{
    return GetInnerXml(element, nodeName, null);
}

private static string GetInnerXml(XmlElement element, string nodeName, string defaultValue)
{
    XmlNode node = element.SelectSingleNode(nodeName);
    return node == null ? defaultValue : node.InnerXml;
}

Apakah ada keuntungan untuk mendeklarasikan metode GetInnerXml () sebagai statis? Tolong, tidak ada tanggapan pendapat, saya punya pendapat.

NerdFury
sumber

Jawaban:

221

Dari halaman aturan FxCop tentang ini:

Setelah Anda menandai metode sebagai statis, kompiler akan memancarkan situs panggilan non-virtual kepada anggota ini. Memancarkan situs panggilan non-virtual akan mencegah pemeriksaan saat runtime untuk setiap panggilan yang memastikan bahwa penunjuk objek saat ini adalah non-nol. Ini dapat menghasilkan perolehan kinerja yang terukur untuk kode yang peka terhadap kinerja. Dalam beberapa kasus, kegagalan untuk mengakses instance objek saat ini merupakan masalah kebenaran.

Scott Dorman
sumber
37
Saya juga akan menambahkan bahwa klausa "statis" tidak membahayakan dan sudah memberikan beberapa "dokumentasi" dengan 1 kata. Ini memberitahu Anda bahwa metode ini tidak menggunakan anggota instance, dan Anda mendapatkan dokumentasi ini hampir gratis
frandevel
20
Saya akan mengatakan: "Jika suatu metode tidak memerlukan akses negara (ini), buatlah itu statis" sebagai aturan umum.
DanMan
3
Untuk kepentingan keseimbangan, ada baiknya menunjukkan bahwa banyak orang pada umumnya menentang metode statis karena mereka merusak polimorfisme, dan berarti objek tidak dapat di-stubbed untuk pengujian. misalnya lihat googletesting.blogspot.co.uk/2008/12/…
Andy
@ Andy - Poin bagus. Salah satu cara untuk menggambar garis adalah dengan melihat apakah metode statis mengakses apa pun di luar parameter yang Anda lewati. Selama itu mandiri dengan cara ini, itu harus mudah untuk diuji, dan tidak perlu untuk mematikan apa pun.
Neil
4
Banyak pengembang tidak terbiasa dengan "private static". Saya telah menggunakannya di basis kode umum tim saya dan itu menyebabkan kebingungan. Sebagai gantinya, itu memberikan manfaat yang sangat kecil. Kami dapat memilih untuk mendidik semua orang di tim, termasuk semua pengembang di masa depan yang menjaga kode, seperti apa artinya. Tetapi manfaat dari beralih metode privat ke privat statis sangat kecil (yaitu menghilangkan ketergantungan pada data instance), itu tidak sepadan dengan usaha dan kebingungan. Metode ini sudah merupakan ruang lingkup pribadi. Ini adalah kekhasan bahasa yang tidak perlu diketahui.
Curtis Yallop
93

Ketika saya menulis sebuah kelas, sebagian besar metode terbagi dalam dua kategori:

  • Metode yang menggunakan / mengubah keadaan instance saat ini.
  • Metode pembantu yang tidak menggunakan / mengubah keadaan objek saat ini, tetapi bantu saya menghitung nilai yang saya butuhkan di tempat lain.

Metode statis berguna, karena hanya dengan melihat tanda tangannya, Anda tahu bahwa pemanggilannya tidak menggunakan atau mengubah keadaan instance saat ini.

Ambil contoh ini:

Perpustakaan kelas publik
{
    buku pencari Buku statis pribadi (Daftar buku <Book>, judul string)
    {
        // kode di sini
    }
}

Jika sebuah instance dari keadaan perpustakaan pernah kacau, dan saya mencoba mencari tahu mengapa, saya dapat mengesampingkan findBook sebagai biang keladinya, hanya dari tanda tangannya.

Saya mencoba untuk berkomunikasi sebanyak mungkin dengan tanda tangan metode atau fungsi, dan ini adalah cara terbaik untuk melakukannya.

Neil
sumber
1
Jenis deklarasi metode-metode di C ++, bukan?
anhoppe
Ya - itu cara lain yang baik untuk menggunakan bahasa untuk menyederhanakan hal-hal dengan membatasi apa yang bisa salah.
Neil
Ini belum tentu benar. Mari kita asumsikan bahwa Librarymemiliki bidang contoh List<Book> _booksuntuk menyimpan buku-bukunya (bukan bagaimana Anda mendesain sebuah Librarykelas tetapi w / e), dan ia meneruskan daftar ini ke findBook, dan metode statis itu memanggil books.Clear()atau books.Reverse()dan seterusnya. Jika Anda memberikan akses metode statis ke referensi ke beberapa keadaan yang bisa berubah, maka metode statis itu bisa sangat mengacaukan keadaan Anda.
sara
1
Benar. Dan dalam hal ini, tanda tangan akan menunjukkan kepada kita bahwa metode ini memiliki akses ke (dan kemampuan untuk mengubah) instance dari Library.
Neil
Untuk hampir semua konstruksi pelindung yang mungkin kita gunakan, ada beberapa cara untuk merusaknya. Tetapi menggunakan mereka masih bijaksana dan membantu mendorong kita ke arah yang benar, menuju "lubang kesuksesan".
Neil
81

Panggilan ke metode statis menghasilkan instruksi panggilan dalam Microsoft intermediate language (MSIL), sedangkan panggilan ke metode instance menghasilkan instruksi callvirt, yang juga memeriksa referensi objek nol. Namun, sebagian besar waktu perbedaan kinerja antara keduanya tidak signifikan.

src: MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx

Marek Takac
sumber
15

Ya, kompiler tidak perlu meneruskan thispointer implisit ke staticmetode. Bahkan jika Anda tidak menggunakannya dalam metode instance Anda, itu masih diteruskan.

Kent Boogaart
sumber
Bagaimana hal ini terkait dengan keunggulan kinerja atau memori saat runtime?
Scott Dorman
11
Melewati parameter tambahan berarti CPU harus melakukan pekerjaan ekstra untuk menempatkan parameter itu dalam register, dan mendorongnya ke tumpukan jika metode instance memanggil metode lain.
Kent Boogaart
5

Ini akan sedikit lebih cepat karena tidak ada parameter ini berlalu (walaupun biaya kinerja memanggil metode mungkin jauh lebih banyak daripada penghematan ini).

Saya akan mengatakan alasan terbaik yang dapat saya pikirkan untuk metode statis pribadi adalah itu berarti Anda tidak dapat secara tidak sengaja mengubah objek (karena tidak ada pointer ini).

Wildebeest gratis
sumber
4

Ini memaksa Anda untuk ingat untuk juga mendeklarasikan setiap anggota kelas-lingkup fungsi menggunakan sebagai statis juga, yang seharusnya menghemat memori membuat item-item untuk setiap contoh.

Joel Coehoorn
sumber
Hanya karena itu adalah variabel kelas-lingkup tidak berarti itu harus statis.
Scott Dorman
3
Tidak, tetapi jika itu digunakan oleh metode statis maka HARUS statis. Jika metode ini tidak statis maka Anda mungkin tidak membuat anggota kelas statis, dan itu akan menghasilkan lebih banyak memori yang digunakan untuk setiap instance kelas.
Joel Coehoorn
2

Saya jauh lebih suka semua metode pribadi menjadi statis kecuali mereka benar-benar tidak bisa. Saya lebih suka yang berikut ini:

public class MyClass
{
    private readonly MyDependency _dependency;

    public MyClass(MyDependency dependency)
    {
        _dependency = dependency;
    }

    public int CalculateHardStuff()
    {
        var intermediate = StepOne(_dependency);
        return StepTwo(intermediate);
    }

    private static int StepOne(MyDependency dependency)
    {
        return dependency.GetFirst3Primes().Sum();
    }

    private static int StepTwo(int intermediate)
    {
        return (intermediate + 5)/4;
    }
}

public class MyDependency
{
    public IEnumerable<int> GetFirst3Primes()
    {
        yield return 2;
        yield return 3;
        yield return 5;
    }
}

atas setiap metode mengakses bidang instance. Kenapa ini? Karena ketika proses penghitungan ini menjadi lebih kompleks dan kelas berakhir dengan 15 metode pembantu pribadi, maka saya BENAR-BENAR ingin dapat menarik mereka ke dalam kelas baru yang merangkum bagian dari langkah-langkah dengan cara yang bermakna secara semantik.

Ketika MyClassmendapat lebih banyak dependensi karena kita perlu login dan juga perlu memberi tahu layanan web (mohon alasan contoh klise), maka sangat membantu untuk dengan mudah melihat metode apa yang memiliki dependensi mana.

Alat-alat seperti R # memungkinkan Anda mengekstrak kelas dari serangkaian metode statis pribadi dalam beberapa penekanan tombol. Coba lakukan ketika semua metode pembantu pribadi sangat erat digabungkan ke bidang contoh dan Anda akan melihat itu bisa sangat sakit kepala.

sara
sumber
-3

Seperti yang telah dinyatakan, ada banyak keuntungan dari metode statis. Namun; perlu diingat bahwa mereka akan hidup di tumpukan untuk kehidupan aplikasi. Saya baru-baru ini menghabiskan satu hari melacak kebocoran memori di Layanan Windows ... kebocoran itu disebabkan oleh metode statis pribadi di dalam kelas yang menerapkan IDisposable dan secara konsisten dipanggil dari pernyataan menggunakan. Setiap kali kelas ini dibuat, memori dicadangkan di heap untuk metode statis di dalam kelas, sayangnya, ketika kelas dibuang, memori untuk metode statis tidak dirilis. Ini menyebabkan jejak memori layanan ini untuk menggunakan memori server yang tersedia dalam beberapa hari dengan hasil yang dapat diprediksi.

James Haumann
sumber
4
Ini tidak masuk akal. Tumpukan tidak pernah menyimpan memori untuk kode untuk metode apa pun , statis atau lainnya. Heap adalah untuk instance objek. Akan ada data pada stack untuk setiap doa dari metode apa pun (untuk menahan memori untuk parameter, nilai pengembalian, penduduk lokal yang tidak diangkat, dll.) Tetapi semua itu akan hilang ketika metode selesai dieksekusi.
Servy