Mengapa menggunakan metode publik di kelas internal?

250

Ada banyak kode di salah satu proyek kami yang terlihat seperti ini:

internal static class Extensions
{
    public static string AddFoo(this string s)
    {
        if (s == null)
        {
            return "Foo";
        }

        return $({s}Foo);
    }
}

Apakah ada alasan eksplisit untuk melakukan hal ini selain "lebih mudah untuk membuat tipe publik nanti?"

Saya menduga itu hanya masalah dalam kasus tepi yang sangat aneh (refleksi di Silverlight) atau tidak sama sekali.

bopapa_1979
sumber
1
Dalam pengalaman saya, itu adalah praktik normal.
phoog
2
@phoog, oke. tapi mengapa itu praktik biasa? Mungkin lebih mudah kemudian mengubah banyak metode ke internal? Perbaikan cepat -> tandai tipe internal saja?
bopapa_1979
itulah yang selalu saya asumsikan. Namun, saya tidak memiliki analisis yang dipikirkan dengan matang, itulah sebabnya saya tidak mengirim jawaban.
phoog
2
Jawaban Eric Lippert meringkaskan pemikiran saya dengan sangat baik, dan juga memunculkan sesuatu yang bersembunyi di otak saya mencoba mencari jalan keluar: implementasi implisit anggota antarmuka harus bersifat publik.
phoog
Bukankah metode itu sama dengan return s + "Foo";? The +operator tidak peduli nol atau string kosong.
Mikkel R. Lund

Jawaban:

418

UPDATE: Pertanyaan ini adalah topik blog saya pada bulan September 2014 . Terima kasih atas pertanyaannya!

Ada banyak perdebatan tentang pertanyaan ini bahkan di dalam tim penyusun itu sendiri.

Pertama, adalah bijaksana untuk memahami aturan. Anggota publik dari kelas atau struct adalah anggota yang dapat diakses oleh apa pun yang dapat mengakses tipe yang mengandung . Jadi anggota publik dari kelas internal secara efektif internal.

Jadi sekarang, dengan kelas internal, haruskah anggotanya yang ingin Anda akses di majelis ditandai sebagai publik atau internal?

Pendapat saya adalah: tandai anggota tersebut sebagai publik.

Saya menggunakan "publik" yang berarti "anggota ini bukan detail implementasi". Anggota yang dilindungi adalah detail implementasi; ada sesuatu tentang hal itu yang akan dibutuhkan untuk membuat pekerjaan kelas yang diturunkan. Anggota internal adalah detail implementasi; sesuatu yang lain di dalam majelis ini membutuhkan anggota untuk bekerja dengan benar. Anggota publik mengatakan "anggota ini mewakili kunci, fungsi terdokumentasi yang disediakan oleh objek ini."

Pada dasarnya, sikap saya adalah: seandainya saya memutuskan untuk membuat kelas internal ini menjadi kelas publik. Untuk melakukan itu, saya ingin mengubah satu hal : aksesibilitas kelas. Jika mengubah kelas internal menjadi kelas publik berarti saya harus juga mengubah anggota internal menjadi anggota publik, maka anggota itu adalah bagian dari area permukaan publik dari kelas tersebut, dan itu seharusnya sudah menjadi publik di tempat pertama.

Orang lain tidak setuju. Ada kontingen yang mengatakan bahwa mereka ingin dapat melirik deklarasi anggota dan segera tahu apakah itu akan dipanggil hanya dari kode internal.

Sayangnya, itu tidak selalu berhasil dengan baik; misalnya, kelas internal yang mengimplementasikan antarmuka internal masih harus memiliki anggota pelaksana yang ditandai sebagai publik, karena mereka adalah bagian dari permukaan publik kelas .

Eric Lippert
sumber
11
Saya suka jawaban ini ... sangat cocok dengan sikap saya terhadap penulisan kode yang mendokumentasikan diri sendiri semaksimal mungkin, dan ruang lingkup adalah cara yang bagus untuk menyiarkan maksud, terutama jika anggota tim Anda yang lain memahami konvensi Anda.
bopapa_1979
10
1 untuk mengatakan apa yang ingin saya katakan tetapi merumuskannya jauh lebih baik daripada yang saya mampu (juga untuk memunculkan sudut antarmuka, meskipun saya perhatikan bahwa itu hanya berlaku untuk implementasi anggota implisit).
phoog
2
Bagian Antarmuka penting - tidak mungkin untuk menerapkan metode antarmuka menggunakan internal, baik deklarasi antarmuka publik atau eksplisit. Jadi kata publik dipenuhi dengan dua makna.
Michael Stum
8
Dari perspektif idealogis, argumen Anda yang mendukung publicsangat meyakinkan. Namun, saya menemukan "tidak selalu berhasil dengan baik ..." menjadi sangat kuat. Kehilangan konsistensi mendevaluasi setiap manfaat "sekilas". Menggunakan internalcara ini berarti secara sengaja membangun intuisi yang terkadang salah. Memiliki intuisi yang sebagian besar benar adalah IMO hal yang mengerikan untuk pemrograman.
Brian
3
Kutipan penting dari posting blog Anda: "Saran saya adalah membahas masalah di antara tim Anda, membuat keputusan, dan kemudian berpegang teguh pada itu."
bopapa_1979
17

Jika kelasnya internal, tidak masalah dari sudut pandang aksesibilitas apakah Anda menandai suatu metode internalatau public. Namun masih bagus untuk menggunakan tipe yang akan Anda gunakan jika kelasnya public.

Sementara beberapa mengatakan bahwa ini memudahkan transisi dari internalke public. Ini juga berfungsi sebagai bagian dari deskripsi metode. Internalmetode biasanya dianggap tidak aman untuk akses tidak terbatas, sementara publicmetode dianggap (sebagian besar) permainan gratis.

Dengan menggunakan internalatau publicseperti yang Anda lakukan di publickelas, Anda memastikan bahwa Anda mengkomunikasikan gaya akses apa yang diharapkan, sementara juga memudahkan pekerjaan yang diperlukan untuk membuat kelas publicdi masa depan.

Guvante
sumber
Saya cenderung membatasi segalanya semaksimal mungkin sambil membuat API yang baik dan memungkinkan konsumen yang saya maksud untuk melakukan apa yang saya inginkan. Saya juga bersama Anda menandai anggota seperti yang saya lakukan jika kelas terbuka untuk umum. Lebih khusus, saya hanya akan menandai setiap anggota publik jika saya menganggapnya selalu aman. Kalau tidak, orang lain yang menandai publik kelas nanti (hal itu terjadi) dapat mengekspos anggota yang tidak aman.
bopapa_1979
@ Eric: Jika Anda ingin melupakan menentukan keamanan suatu metode sampai Anda siap, itu bagus, tetapi saya hanya merujuk pada metode yang dianggap aman, dalam hal ini tidak ada pemaparan.
Guvante
10

Saya sering menandai metode saya di kelas internal publik daripada internal sebagai a) itu tidak masalah dan b) Saya menggunakan internal untuk menunjukkan bahwa metode ini internal sengaja (ada beberapa alasan mengapa saya tidak ingin mengekspos ini metode dalam kelas publik.Oleh karena itu, jika saya memiliki metode internal saya benar-benar harus memahami alasan mengapa itu internal sebelum mengubahnya ke publik sedangkan jika saya berurusan dengan metode publik di kelas internal saya benar-benar harus memikirkan mengapa kelas internal sebagai lawan mengapa setiap metode internal.

Ɖiamond ǤeezeƦ
sumber
Terima kasih atas jawabannya. Saya cenderung keras kepala bersikeras bahwa "segalanya" penting ketika coding, :)
bopapa_1979
1
Anda benar Eric, itu sedikit membuang komentar. Semoga sisa jawaban saya bermanfaat. Saya pikir jawaban Eric Lippert adalah apa yang saya coba ungkapkan tetapi dia menjelaskannya dengan jauh lebih baik.
Ɖiamond ǤeezeƦ
8

Saya menduga bahwa "lebih mudah untuk membuat tipe publik nanti?" Apakah itu.

Aturan pelingkupan berarti bahwa metode tersebut hanya akan terlihat sebagai internal- jadi tidak masalah apakah metode tersebut ditandai publicatau tidak internal.

Satu kemungkinan yang terlintas dalam pikiran adalah bahwa kelas tersebut bersifat publik dan kemudian diubah menjadi internaldan pengembang tidak repot-repot mengubah semua metode pengubah aksesibilitas metode.

Oded
sumber
1
+1 untuk memakukan skenario "kelas publik menjadi internal" yang jelas.
bopapa_1979
8

Dalam beberapa kasus, mungkin juga tipe internal mengimplementasikan antarmuka publik yang berarti bahwa setiap metode yang didefinisikan pada antarmuka itu masih harus dinyatakan sebagai publik.

Trevor Pilley
sumber
2

Itu sama, metode publik akan benar-benar ditandai sebagai internal karena itu di dalam kelas internal, tetapi memiliki kelebihan (seperti yang Anda tuju), jika Anda ingin menandai kelas sebagai publik, Anda harus mengubah lebih sedikit kode.

Mario Corchero
sumber
2
sudah ada pertanyaan terkait: stackoverflow.com/questions/711361/…
Mario Corchero
0

internalkata anggota itu hanya dapat diakses dari dalam majelis yang sama. Kelas lain dalam majelis itu dapat mengakses internal publicanggota, tetapi tidak akan dapat mengakses privateatau protectedanggota, internalatau tidak.

Ryan P
sumber
Tetapi jika metode ditandai internalbukan public, visibilitas mereka tidak akan berubah. Saya percaya itulah yang ditanyakan OP.
Oded
1
@ zapthedingbat - postingan faktanya benar, tetapi apakah ini benar-benar menjawab pertanyaan?
Oded
1
Benar, pertanyaannya adalah MENGAPA menandai mereka seperti itu. Saya mengerti dasar-dasar ruang lingkup. Terima kasih atas usahanya!
bopapa_1979
0

Saya benar-benar berjuang dengan ini hari ini. Sampai sekarang saya akan mengatakan bahwa semua metode harus ditandai dengan internaljika kelas itu internaldan akan menganggap hal lain hanya pengkodean atau kemalasan yang buruk, khususnya dalam pengembangan usaha; Namun, saya harus sub kelas publickelas dan menimpa salah satu metode itu:

internal class SslStreamEx : System.Net.Security.SslStream
{
    public override void Close()
    {
        try
        {
            // Send close_notify manually
        }
        finally
        {
            base.Close();
        }
    }
}

Metode itu HARUS publicdan membuat saya berpikir bahwa sebenarnya tidak ada titik logis untuk menetapkan metode internalkecuali jika memang benar-benar harus, seperti kata Eric Lippert.

Sampai sekarang saya tidak pernah benar-benar berhenti untuk memikirkannya, saya hanya menerimanya, tetapi setelah membaca posting Eric itu benar-benar membuat saya berpikir dan setelah banyak berunding itu masuk akal.

Badai
sumber
0

Memang ada perbedaan. Dalam proyek kami, kami telah membuat banyak kelas internal, tetapi kami melakukan uji unit dalam perakitan lain dan dalam info perakitan kami, kami menggunakan InternalsVisibleTo untuk memungkinkan perakitan UnitTest memanggil kelas internal. Saya perhatikan jika kelas internal memiliki konstruktor internal, kami tidak dapat membuat instance menggunakan Activator.CreateInstance di unit test assembly untuk beberapa alasan. Tetapi jika kita mengubah konstruktor ke publik tetapi kelas masih internal, itu berfungsi dengan baik. Tapi saya kira ini adalah kasus yang sangat langka (Seperti yang Eric katakan dalam posting asli: Reflection).

Farrah Jiang
sumber
0

Saya pikir saya punya pendapat tambahan tentang ini. Pada awalnya, saya bertanya-tanya tentang bagaimana masuk akal untuk menyatakan sesuatu kepada publik di kelas internal. Kemudian saya berakhir di sini, membaca bahwa mungkin baik jika Anda kemudian memutuskan untuk mengubah kelas menjadi publik. Benar. Jadi, sebuah pola terbentuk dalam pikiran saya: Jika itu tidak mengubah perilaku saat ini, maka permisif, dan biarkan hal-hal yang tidak masuk akal (dan tidak sakit) dalam keadaan kode saat ini, tetapi nanti akan, jika Anda ubah deklarasi kelas.

Seperti ini:

public sealed class MyCurrentlySealedClass
{
    protected void MyCurretlyPrivateMethod()
    {
    }
}

Menurut "pola" yang telah saya sebutkan di atas, ini seharusnya baik-baik saja. Ini mengikuti ide yang sama. Berperilaku sebagai privatemetode, karena Anda tidak dapat mewarisi kelas. Tetapi jika Anda menghapus sealedkendala, itu masih valid: kelas yang diwarisi dapat melihat metode ini, yang benar-benar apa yang ingin saya capai. Tetapi Anda mendapat peringatan:, CS0628atau CA1047. Keduanya adalah tentang tidak menyatakan protectedanggota di sealedkelas. Selain itu, saya telah menemukan persetujuan penuh, tentang hal itu tidak masuk akal: peringatan 'Anggota yang dilindungi di kelas tertutup' (kelas tunggal)

Jadi setelah peringatan dan diskusi ini dikaitkan, saya telah memutuskan untuk menjadikan semuanya internal atau kurang, di kelas internal, karena lebih sesuai dengan jenis pemikiran itu, dan kami tidak mencampur "pola" yang berbeda.

Hix
sumber
Saya secara drastis lebih suka melakukannya dengan cara (atau setidaknya untuk alasan) kata Eric Lippert. Artikelnya pasti layak dibaca.
bopapa_1979