C # - Mengapa awalan pada bidang tidak disarankan?

19

Kembali di masa lalu, kami melakukan notasi Hongaria. Itu sekarang dianggap ketinggalan jaman , dan sebagian besar saya tidak menggunakannya lagi, tapi saya masih menemukan penggunaan m_awalan untuk menunjukkan bidang anggota.

Bagi saya, jika saya membaca kode orang lain, dan saya melihat ini:

count = 3;

Saya berasumsi itu countadalah variabel lokal untuk fungsi itu dan saya sedang melakukan sesuatu yang akan digunakan di tempat lain dalam fungsi; jika saya melihat ini:

m_count = 3;

Saya segera menyadari bahwa saya memperbarui keadaan objek.

Pedoman gaya Microsoft mengatakan bahwa itu adalah cara yang salah untuk melakukan sesuatu. Saya seharusnya memberi nama bidang non-publik saya persis seperti variabel sementara yang didefinisikan dalam fungsi. Tidak m_, bahkan garis bawah yang sederhana.

Ya, kita dapat mendefinisikan gaya pengkodean kita sendiri, tetapi kemudian saya harus bergulat dengan berbagai alat analisis kode statis, untuk meyakinkan mereka bahwa cara kita melakukan sesuatu adalah OK.

Saya senang untuk mengubah ke gaya Microsoft, tetapi saya ingin tahu mengapa semuanya seperti itu.

Mengapa sekarang dianggap buruk untuk dapat mengetahui apakah suatu variabel adalah fungsi lokal atau anggota?

PS Ini sangat mirip dengan Apa praktik terbaik yang dianggap saat ini mengenai kata kunci "ini" di depan bidang dan metode dalam c #? , tapi saya bertanya tentang m_tidakthis.

PPS Juga lihat Mengapa Microsoft membuat parameter, variabel lokal, dan bidang pribadi memiliki konvensi penamaan nama yang sama?

Betty Crokker
sumber
9
Bukankah C # memiliki thiskata kunci? Tidak bisakah Anda merujuk pada anggota yang menggunakan this, seperti this.count?
FrustratedWithFormsDesigner
3
Awalan m_ adalah isme C ++ - ism di mana ia menghindari bentrok nama antara bidang dan metode. Dalam C # ini bukan masalah karena nama metode harus dimulai dengan huruf besar, bidang dengan huruf kecil.
amon
4
Jika Anda mencetak kode pada 2017, Anda melakukan sesuatu yang salah. Dalam dua skenario lainnya, itu harus cukup jelas bahwa counttidak muncul begitu saja karena tidak dinyatakan dalam metode. Terus terang argumen "out of IDE" BENAR-BENAR lemah. Terutama karena bahkan ada alat peninjau kode yang bekerja DI IDE.
Andy
4
Masih relevan posting dari Joel .
Kasey Speakman

Jawaban:

19

Ketika mereka bekerja pada API untuk Windows, Microsoft merekomendasikan penggunaan Notasi Hongaria, menggunakan 'm_', serta 'i', 'sz', dll. Pada saat itu, ini berguna karena IDE tidak kuat cukup untuk menunjukkan informasi ini kepada Anda.

C #, di sisi lain, memiliki IDE yang sangat kuat sejak awal.

Jadi mereka membuat rekomendasi dalam Panduan Penamaan Microsoft untuk C # untuk bidang statis atau terlindungi publik:

 DO use PascalCasing in field names.
 DO name fields using a noun, noun phrase, or adjective.
X DO NOT use a prefix for field names.

Sekarang Anda dapat mengarahkan mouse dengan mouse Anda, atau tekan CTRL + K + W, dan mendapatkan semua informasi tentang anggota, Microsoft sampai pada penentuan bahwa awalan adalah bentuk yang buruk; mereka adalah solusi manual untuk masalah yang sudah diselesaikan.

Bidang pribadi secara khusus dikecualikan dari pedoman, tetapi Microsoft tampaknya sampai pada kesimpulan bahwa ini adalah kasus bahkan untuk bidang pribadi maju secara internal, yang dapat Anda lihat jika Anda mengarahkan Resharper di .NET 4.5 atau .NET Core.

Gunakan alat Anda, jangan lakukan secara manual.

Kevin Fee
sumber
2
Jawaban yang sama dengan Andy ... ya tapi ... ada banyak situasi di mana saya melihat kode di luar IDE. Contoh - (1) menggabungkan alat. (2) alat ulasan kode. (3) (terkesiap) cetakan.
Betty Crokker
Andy memposting secara harfiah sama seperti yang saya lakukan. Saya melihat "1 komentar baru" muncul ketika saya mengklik "tambahkan jawaban". Sejauh alat-alat itu, dua di antaranya sudah ada di IDE. Cetakan ... mengapa kamu melakukan itu?
Kevin Fee
1
Pertanyaan awal saya masih belum terjawab ... ya, Microsoft mengatakan jangan gunakan m_ dan pabrikan alat mengikuti itu, tapi itu bukan alasan teknis untuk menggunakan m_, itu yang sering disebut "banding ke otoritas". Satu-satunya alasan teknis yang saya lihat tidak menggunakan m_ berasal dari Timothy Truckle dan saya tidak memahaminya ...
Betty Crokker
8
@BettyCrokker Karena m_ menambahkan sama sekali tidak ada nilai. IDE memberi tahu Anda anggota atau tidak, sehingga m_ redunden. Adakah mengapa Anda terpaku pada m_? Kenapa tidak l_ (untuk lokal)? Kenapa tidak afsdfjdskfjas_? Saya akan menurunkan pertanyaan, karena itu adalah argumen agama yang konyol. Melakukan apapun yang Anda inginkan. Pedoman yang Anda ketuk juga mengatakan "Pedoman penamaan bidang berlaku untuk bidang publik dan dilindungi statis . Bidang internal dan pribadi _not_ dicakup oleh pedoman , dan bidang contoh publik atau dilindungi tidak diizinkan oleh pedoman desain anggota."
Andy
1
@ BettyCrokker OK, tapi Anda bertanya tentang pedoman yang dibuat dengan asumsi itu. Anda juga mengeluh tentang alat statis yang kemungkinan menggunakan asumsi itu juga, karena "tidak ada" (dalam margin kesalahan statistik yang dapat diterima) mencetak kode C # mereka. Saya tidak tahu alat analisis statistik apa yang Anda gunakan, tetapi Resharper cukup spesifik: Bidang pribadi adalah "_lowerCase". Anggota publik dari jenis apa pun atau "UpperCase", dan penduduk setempat adalah "lowerCase". Menyimpan pada "m" sebenarnya terlihat cukup bagus.
Kevin Fee
17

C # tidak memiliki variabel global, sehingga hanya menyisakan variabel lokal dan bidang kelas.

Dan jika Anda memiliki begitu banyak variabel lokal sehingga Anda lupa apakah pengenal itu salah satu, Anda pasti telah melanggar salah satu pedoman untuk mengelola kompleksitas dengan sangat menyedihkan.

Cobalah untuk mengekstrak parameter-objek, cobalah untuk membagi fungsi Anda menjadi beberapa yang lebih sederhana, Anda tentu harus memperbaiki kode Anda kecuali jika Anda suka tenggelam dalam hal-hal kecil dan rumit, serta tidak memedulikan kemampuan pemeliharaan.

Sekarang kita telah menetapkan bahwa tujuan "this-is-a-member" -dekorasi tidak lagi berlaku karena fungsi-ruang lingkup harus terlalu kecil dan ruang lingkup global tidak ada, ada satu kelemahan dari penanda tersebut: Mereka menghambat memindahkan argumen / variabel lokal ke anggota, atau sebaliknya.

Deduplicator
sumber
Setelah Anda dot ke dalamnya, itu juga bisa menjadi kelas atau namespace.
CodesInChaos
3
Saya tidak berpikir ini benar-benar menjawab pertanyaan itu.
Vladimir Stokic
5
@ FrankHileman Sebenarnya, benar. Ini menjelaskan mengapa tidak ada alasan yang baik untuk menghapus nama.
Deduplicator
2
"menjelek"? Jika ini masalahnya, ini hanya pertanyaan opini. Setiap orang dapat memiliki pendapat berbeda tentang keburukan. Ada alasan untuk memilih satu konvensi daripada yang lain, tetapi tidak ada konvensi standar dalam kasus ini.
Frank Hileman
1
@Deduplicator beauty ada di mata yang melihatnya. Kebiasaan yang dulu saya anggap jelek, sekarang saya hargai sebagai berguna.
Frank Hileman
11

Mengapa pengembang menghindari menambahkan ruang nama dengan direktif namespace menggunakan?

System.DateTime() jauh lebih eksplisit daripada DateTime() . Ini memberitahu saya apa yang saya hadapi. Apakah hanya karena kita pengetik yang malas?

Tidak. Kami pengetik yang malas, tapi bukan itu sebabnya.

Kami lebih suka gaya pengkodean yang memungkinkan kami mengabaikan detail dan fokus pada abstraksi. Memaksa nama untuk mengomunikasikan detail struktur mengganggu. Ketika saya bekerja pada algoritma yang rumit, saya tidak ingin nama yang bersikeras mengingatkan saya setiap detail kecil tentang hal yang saya kerjakan. Saya hanya perlu nama agar saya tidak bingung Timerdan DateTime. Saya akan khawatir jika itu kompatibel di tempat lain.

Itu alasan yang sama Anda tidak ingin dua orang di tim Anda bernama Jon. Fakta bahwa mereka memiliki nama belakang bukan alasan untuk memberi mereka awalan atau sufiks. Aku hanya akan memanggilmu Skeet. Apa pun yang lebih adalah rasa sakit.

candied_orange
sumber
2
Ini sepertinya tidak menjawab pertanyaan. Tidak ada preferensi atau konvensi umum untuk bidang pribadi di .net.
Frank Hileman
12
@ FrankHileman Secara umum, kami lebih suka nama baik. Konvensi tidak membuat nama baik. Konvensi membuat nama seperti McOhSilahkan Von StopItAlreadyStine.
candied_orange
Konvensi hanya untuk membuatnya lebih mudah untuk bekerja dengan kode pengembang yang berbeda. Jawaban Anda memang ditujukan pada bahasa Hongaria, tetapi tidak ada konvensi untuk bidang pribadi, jadi pertanyaannya didasarkan pada asumsi yang salah.
Frank Hileman
7

Mari kita sedikit berkembang.

Ada 3 gaya awalan umum, yang semuanya kadang-kadang ditemui dalam kode c #:

  • m_
  • _
  • ini.

Awalan seperti itu biasanya digunakan dalam implementasi privat kelas . Rekomendasi Microsoft terutama tentang bagian-bagian kelas yang terbuka.

Keuntungan menggunakan m_over _adalah bahwa awalan bisa sama di seluruh basis kode Anda jika Anda menggunakan c # serta bahasa di mana menggunakan _sebagai awalan tidak diperbolehkan . * Keuntungan m_lebih dari this.itu adalah lebih pendek dan bahwa Anda tidak akan secara tidak sengaja lupakan awalannya.

Keuntungan _lebih m_adalah lebih pendek dan segala sesuatu yang dimulai dengan awalan diurutkan di atas disortir berdasarkan abjad oleh alat. Keuntungan _lebih dari this.itu adalah lebih pendek dan Anda tidak akan sengaja melupakan awalan.

Keuntungan this.lebih m_dan _adalah bahwa Anda dapat menggunakannya dalam basis kode di mana _atau m_tidak konvensi yang diterima dan universal. Itu juga berarti tidak ada yang perlu tahu tentang _atau m_konvensi, yang dapat dilihat sebagai hal yang lebih sederhana. Sebagai kerugian, karena kompiler tidak peduli dengan awalan ini, this.awalan kadang-kadang akan hilang, dan karenanya tidak dapat diandalkan sebagai indikator.


* Setelah Anda mulai mengakses kelas C # yang digunakan _dari C ++ / CLI (yang benar-benar tidak boleh digunakan _), Anda akan melihat bahwa menyetujui awalan umum lebih kompleks dari yang seharusnya. Memutuskan untuk tidak memiliki awalan menghilangkan kebisingan itu. Gabungkan ini dengan jawaban Deduplicator, yang saya akan parafrase sebagai "keuntungan dari awalan hampir dapat diabaikan", dan itu memberi kita: "Ada masalah kecil ketika menggunakan awalan, dan terbalik kecil, jadi itu adalah pilihan yang valid untuk tidak gunakan mereka ".


Ada pertanyaan lama tentang stackoverflow yang terkait dengan ini.

Peter - Unban Robert Harvey
sumber
1
Perbandingan yang bagus. Namun, saya menemukan bahwa tidak menggunakan awalan bekerja dengan baik dalam praktiknya.
Phil1970
6

Perlu dicatat bahwa panduan gaya MS hanya berbicara tentang metode dan variabel publik dan yang dilindungi. yaitu yang devs lain akan melihat apakah mereka menggunakan perpustakaan Anda.

Gagasannya adalah bahwa perpustakaan Microsoft diberikan tampilan dan rasa standar untuk pengembang memakannya.

Anda bebas menggunakan gaya apa pun yang Anda suka pada variabel pribadi atau lokal Anda.

Setelah mengatakan bahwa awalan variabel tidak disarankan secara umum karena sejumlah alasan

  • Mereka bisa salah, dan karenanya menyesatkan
  • Jika Anda mengawali dengan tipe variabel tidak jelas bagaimana Anda menangani kelas yang telah Anda buat.
  • Ada sejumlah konvensi dan mereka tidak selalu setuju. Apa yang Anda temukan membantu dev lain mungkin tidak membantu
  • Dalam hal variabel anggota Anda dapat menggunakan ini 'ini.' kata kunci untuk menunjukkan ruang lingkup dan penyusun akan menegakkannya.
Ewan
sumber
2
Awalnya saya tidak menggunakan awalan sama sekali untuk bidang. Kemudian, saya beralih menggunakan karakter "_" tunggal, karena saya melihat orang lain menggunakannya karena memindahkan semua bidang ke bagian atas daftar anggota yang diurutkan berdasarkan abjad ketika Anda menggunakan kotak daftar turun bawah IDE. Kurangnya konvensi standar dapat mengganggu ketika membaca kode yang ditulis oleh banyak pengembang yang berbeda.
Frank Hileman
setelah beberapa saat Anda melihat begitu banyak gaya yang berbeda Anda mengabaikannya. Jika Anda mencoba menegakkan gaya, Anda akan terus-menerus memperbaiki segala sesuatu
Ewan
4
Jika Anda menerapkan "Mereka bisa salah, dan karenanya menyesatkan" untuk sebagian besar apa pun, Anda dengan cepat menemukan bahwa Anda seharusnya tidak memberi nama variabel atau fungsi - mereka mungkin salah! Dan saya menduga bahwa poin kedua Anda seharusnya mengatakan "kelas yang belum Anda buat"? Atau kalau tidak, saya tidak memahaminya ... Bagaimanapun, ini mulai terdengar seperti memiliki awalan garis bawah tunggal untuk bidang non-publik adalah standar tidak resmi, itu mungkin arah yang akan kita tuju.
Betty Crokker
beberapa hal diperiksa oleh kompiler, jadi m_count mungkin bukan variabel anggota, tetapi this.count akan selalu menjadi
Ewan
banyak penggunaan ppl _ tetapi hal-hal berubah dari waktu ke waktu, Anda akan menemukan bahwa kode yang ditulis untuk 'praktik terbaik' tahun lalu tidak cocok dengan konvensi tahun ini
Ewan
4

Bagi saya, jika saya membaca kode orang lain, dan saya melihat ini:

count = 3;

Saya berasumsi bahwa 'menghitung' adalah variabel lokal untuk fungsi itu dan saya sedang melakukan sesuatu yang akan digunakan di tempat lain dalam fungsi

Dan Anda akan benar jika Anda membaca kode sumber yang menghormati konvensi gaya C #. Dalam kode seperti itu:

this.count = 3;

memberikan nilai ke bidang.

count = 3;

memberikan nilai ke variabel lokal.

Oleh karena itu, konvensi gaya C # jelas dan tidak ambigu. Mereka memaksa Anda untuk tidak menggunakan awalan hanya karena Anda tidak membutuhkannya.

Adapun kode sumber yang penulis memutuskan untuk menggunakan konvensi pribadi mereka, Anda harus bertanya kepada mereka secara pribadi mengapa mereka membuat pilihan untuk melakukannya. Jika mereka tidak menggunakan awalan seperti garis bawah, sementara tidak menggunakan this.salah satu, itu akan secara efektif menyebabkan tidak hanya sulit untuk membaca kode, tetapi juga kasus-kasus di mana konvensi tambahan akan diperlukan:

public class Hello
{
    private string greetings;

    public Hello(string greetings)
    {
        greetings = greetings; // Wait, what is that?!
    }
}

Bukankah C # memiliki kata kunci ini? Tidak bisakah Anda merujuk pada anggota yang menggunakan ini, seperti this.count?

Ya, tapi (1) lebih banyak mengetik, dan (2) mudah dilupakan. Jika bidang tersebut bernama m_count, saya tidak harus ingat untuk mengetik this.m_count

Namun di sini, Anda salah.

Lebih banyak mengetik saat Anda menulis kode di Notepad. Dengan IDE dengan pelengkapan otomatis atau, lebih baik, IntelliSense, perbandingan antara this.countdan m_counttidak sejelas itu. Perhatikan tanda Shift+ yang -diperlukan untuk mengetik garis bawah.

Adapun "mudah dilupakan," lagi, ini hanya relevan untuk pengguna Notepad. Tidak hanya StyleCop dan Resharper tidak akan membiarkan Anda lupa menempatkan this.ketika dibutuhkan, tetapi setelah beberapa jam pemrograman, meletakkan this.ketika dibutuhkan menjadi kebiasaan.

Arseni Mourzenko
sumber
6
Saya menemukan bahwa menggunakan thishanya ketika Anda membutuhkannya menghasilkan perasaan yang sangat tidak konsisten dan mengganggu saya terlalu sering. Jika Anda akan menggunakan thisalih-alih awalan, saya yakin Anda harus selalu menggunakannya. Dalam hal ini, itu menjadi awalan dan Anda mungkin juga menggunakannya _.
RubberDuck
1
RubberDuck benar. "ini." adalah awalan, meskipun, itu memang memiliki arti kompiler.
Frank Hileman
4

Awalan "anggota" adalah semacam detail implementasi. Ini mengalihkan perhatian Anda dari domain masalah ke domain solusi teknis yang bias pikiran Anda ketika memikirkan kemungkinan refactoring. - saya

dapatkah Anda menjelaskan lebih lanjut? Hormat saya satu-satunya alasan mengapa saya tidak menggunakan awalan dan saya tidak memahaminya ... (maksud saya, hal-hal lain yang dikatakan orang adalah alasan mengapa saya tidak harus menggunakannya, yang tidak sama dengan mengapa saya seharusnya tidak) - Betty Crokker

Maksud saya adalah memperluas jawaban @CandiedOrange dan @Ewan.

Awalan membuat refactoring lebih sulit

Saat kode Anda berkembang, variabel dan metode dapat mengubah cakupannya. Misalnya. Anda dapat membuat metode pribadi dan kemudian menemukan bahwa itu harus tersedia untuk kelas (baru) lainnya juga. Serupa dapat terjadi pada parameter metode dan variabel lokal.

Katakanlah Anda membuat kalkulator Pajak. Menurut prinsip lingkup visibilitas sewa untuk variabel Anda mulai dengan metode yang menggunakan keduanya, tarif pajak dan nilai dasar sebagai parameter:
(contohnya mungkin terlihat Java-ish ...)

class TaxCalculator{
   double Calculate(double p_TaxRateInpercent, double p_BaseValue){
     return (100+p_TaxRateInpercent)/100 * p_BaseValue;
   }
} 

selanjutnya Anda harus menerapkan operasi terbalik dan menurut TDD Anda melakukannya dengan sedikit usaha:

class TaxCalculator{
   double Calculate(double p_TaxRateInpercent, double p_BaseValue){
     return (100+p_TaxRateInpercent)/100 * p_BaseValue;
   }
   double CalculateBase(double p_TaxRateInpercent, double p_TaxedValue){
     return p_TaxedValue/((100+p_TaxRateInpercent)/100);
   }
} 

TDD berikutnya ingin Anda mengubah kode menjadi lebih bersih yang mengurangi daftar parameter kedua metode.
(Ya, Anda akan mengekstraksi perhitungan berlipat ganda terlebih dahulu, tetapi biarkan saya mengerti maksud saya ...)
Solusi yang jelas adalah mengubah tarif pajak menjadi variabel anggota dengan meneruskannya sebagai parameter konstruktor.

class TaxCalculator{
   double m_TaxRateInpercent;
   TaxCalculator(double p_TaxRateInpercent){
     m_TaxRateInpercent = p_TaxRateInpercent;
   }
   double Calculate(double p_BaseValue){
     return (100+m_TaxRateInpercent)/100 * p_BaseValue;
   }
   double CalculateBase(double p_TaxedValue){
     return p_TaxedValue/((100+m_TaxRateInpercent)/100);
   }
} 

Seperti yang Anda lihat, kami harus mengubah semua baris metode yang ada (setiap baris yang kami gunakanp_TaxRateInpercent adalah tepat.

Masalahnya adalah, Anda tidak memiliki dukungan dari IDE Anda untuk melakukan penggantian nama di seluruh kelas. Satu-satunya membantu pencarian / penggantian yang juga akan mengubah konstruktor atau bagian apa pun yang secara tidak sengaja berisi string p_TaxRateInpercent.
Anda IDE mungkin menawarkan perubahan ke ... refactoring untuk nama variabel yang tidak ditentukan, tetapi ini mungkin terbatas pada ruang lingkup metode ini

Tanpa awalan hanya tanda tangan metode yang akan berubah. Tidak perlu mengganti nama sama sekali.


Awalan riwayat SCM yang berantakan ketika diubah

Juga SCM mencatat perubahan awalan sebagai perubahan dalam logika meskipun logika tidak berubah! Sejarah SCM berantakan dengan perubahan teknis ini menyembunyikan apa yang penting dan meningkatkan risiko konflik dengan perubahan (logika nyata) orang lain.

Timothy Truckle
sumber
1

Saya menggunakan awalan _ untuk semua variabel anggota. Saya benci awalan 'ini' karena, sementara beberapa orang mengklaim itu adalah cara yang tepat untuk melakukan sesuatu - ini menambah banyak noise / kekacauan pada basis kode Anda. Satu garis bawah juga merupakan praktik umum dalam sampel Microsoft.

Jadi, dalam contoh Anda, saya harus:

int _count = 10;
Eternal21
sumber