Access modifier menentukan kode mana yang boleh memakai sebuah tipe atau member. Dengan access modifier, sebuah class memisahkan bagian yang diandalkan kode lain (permukaan publiknya) dari bagian yang bebas diubahnya (bagian internalnya). C# punya enam access modifier, ditambah default yang kamu dapat saat tidak menulis apa pun.
Enam modifier
| Modifier | Tipe yang memuat | Tipe turunan, assembly sama | Kode lain, assembly sama | Tipe turunan, assembly lain | Kode lain, assembly lain |
|---|---|---|---|---|---|
public | ya | ya | ya | ya | ya |
protected internal | ya | ya | ya | ya | tidak |
protected | ya | ya | tidak | ya | tidak |
internal | ya | ya | ya | tidak | tidak |
private protected | ya | ya | tidak | tidak | tidak |
private | ya | tidak | tidak | tidak | tidak |
Assembly adalah satu project yang sudah di-compile: file .dll atau .exe yang dihasilkannya. "Assembly yang sama" berarti "project yang sama", itulah sebabnya internal berfungsi sebagai "terlihat oleh kodeku, tersembunyi dari pengguna library-ku".
private dan public: enkapsulasi
private adalah default untuk member dan pilihan yang tepat untuk sebagian besar field. Class menyediakan apa yang dibutuhkan pemanggil lewat method dan property public, dan method-method itu menjaga data object tetap konsisten.
Output:
False
True
Priya: 180
Karena balance bersifat private, satu-satunya cara mengubahnya adalah lewat Deposit dan TryWithdraw, dan keduanya menerapkan aturannya. Tidak ada kode lain di program yang bisa membuat saldo negatif, bagaimanapun kode itu ditulis. Inilah manfaat enkapsulasi: aturannya ada di satu tempat.
private berlaku per tipe, bukan per object. Method milik Account boleh membaca other.balance pada instance Account yang lain, dan begitulah biasanya Equals dan method pembanding ditulis.
protected: terlihat oleh class turunan
Member protected tersembunyi dari dunia luar, tetapi tersedia untuk class yang mewarisi class yang mendeklarasikannya.
Output:
Sam: 4000.00
Rita: 6400.00
Ada satu aturan yang sering mengejutkan. Di dalam Manager, kamu boleh memakai baseSalary pada this atau pada Manager lain, tetapi tidak pada sembarang Employee:
class Manager : Employee
{
public decimal Compare(Employee other)
{
return baseSalary - other.baseSalary;
// error CS1540: Cannot access protected member 'Employee.baseSalary' via a qualifier
// of type 'Employee'; the qualifier must be of type 'Manager' (or derived from it)
}
}
Alasannya: other bisa saja sebuah Contractor yang juga diturunkan dari Employee, dan protected memberi akses ke cabang hierarkimu sendiri, bukan ke cabang saudaramu.
Field protected mengikat setiap class turunan ke field itu selamanya. Banyak codebase lebih memilih property atau method protected, atau tetap membuat field private dan hanya memberi class turunan apa yang dibutuhkannya.
internal: terlihat di dalam assembly
Member dan tipe internal bisa dipakai oleh kode apa pun di project yang sama dan tidak oleh apa pun di luarnya. Sebuah library memakainya untuk class pembantu yang diandalkan class public-nya:
// In the MyShop.Pricing library project
public class PriceCalculator
{
public decimal Total(Cart cart) => TaxRules.Apply(cart.Subtotal);
}
internal static class TaxRules // callers of the library cannot see this class
{
internal static decimal Apply(decimal amount) => amount * 1.2m;
}
Tipe tingkat atas bersifat internal saat kamu tidak menulis modifier. Itulah sebabnya class yang lupa kamu tandai public di sebuah class library "hilang" dari project yang mereferensikannya.
Project unit test adalah assembly terpisah, jadi project itu juga tidak bisa melihat kode internal. Solusi standarnya adalah sebuah attribute di library:
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("MyShop.Pricing.Tests")]
protected internal dan private protected
Dua modifier ini menggabungkan modifier sebelumnya dengan cara yang berlawanan, dan namanya mudah tertukar:
protected internaladalah protected atau internal: kode apa pun di assembly yang sama, ditambah class turunan di assembly lain. Ini yang lebih luas.private protected(C# 7.2) adalah protected dan internal: hanya class turunan yang juga berada di assembly yang sama. Ini yang lebih sempit, untuk class dasar yang titik perluasannya harus tetap di dalam library-mu.
public class ReportBase
{
protected internal string Title; // same assembly, or subclasses anywhere
private protected int RowLimit = 500; // subclasses in this assembly only (C# 7.2)
}
Default saat kamu tidak menulis apa pun
| Tempat | Default | Yang diizinkan |
|---|---|---|
| Tipe yang dideklarasikan di namespace | internal | public, internal, file (C# 11) |
| Member class | private | keenamnya |
| Member struct | private | public, internal, private (struct tidak bisa diwarisi) |
| Tipe bersarang | private | keenamnya |
| Member interface | public | modifier eksplisit boleh sejak C# 8 |
| Member enum | public | tidak ada |
Menulis modifier secara eksplisit hanya butuh satu kata dan menghilangkan pertanyaan bagi pembaca berikutnya, jadi sebagian besar panduan gaya meminta modifier ditulis meskipun sama dengan default-nya.
Akses di tingkat accessor
Sebuah property atau indexer bisa memberi salah satu accessor-nya modifier yang lebih sempit daripada property itu sendiri:
Output:
report.pdf: 100%
Modifier accessor harus lebih ketat daripada modifier property-nya, dan hanya salah satu dari dua accessor yang boleh punya modifier.
Aksesibilitas yang tidak konsisten
Member public tidak boleh mengekspos tipe yang visibilitasnya lebih sempit daripada member itu, karena pemanggil akan menerima sesuatu yang tidak boleh mereka sebut namanya:
internal class Discount { }
public class Checkout
{
public Discount Current() => null;
// error CS0050: Inconsistent accessibility: return type 'Discount' is less accessible than method 'Checkout.Current()'
}
Aturan yang sama menghasilkan CS0051 untuk tipe parameter dan CS0053 untuk tipe property. Atasi dengan membuat tipenya seterlihat member-nya, atau membuat member-nya setersembunyi tipenya.
Memilih modifier
Mulailah dengan modifier paling ketat yang masih berfungsi, dan perluas hanya saat ada pemanggil yang membutuhkannya. Membuat sesuatu lebih terlihat belakangan itu mudah dan tidak pernah merusak siapa pun; membuat sesuatu kurang terlihat merusak setiap pemanggil yang memakainya. Dalam praktiknya: field private, member yang menjadi tujuan class public, method pembantu private, dan tipe khusus library internal.
Pertanyaan yang sering diajukan
Apa saja access modifier di C#?
Ada enam: public (kode mana pun), private (hanya tipe yang memuatnya), protected (tipe yang memuatnya dan tipe turunannya), internal (kode apa pun di assembly yang sama), protected internal (assembly yang sama, atau tipe turunan di mana saja) dan private protected (tipe turunan di assembly yang sama, C# 7.2). C# 11 menambahkan file untuk tipe yang hanya terlihat di satu file sumber.
Apa access modifier default di C#?
Member dari class atau struct (field, method, property, tipe bersarang) secara default private. Tipe tingkat atas (class yang dideklarasikan langsung di dalam namespace) secara default internal. Member interface dan member enum bersifat public.
Apa arti protected di C#?
Member protected terlihat di dalam class-nya sendiri dan di dalam class mana pun yang diturunkan darinya, tetapi tidak oleh kode lain. Class turunan hanya bisa memakainya lewat tipenya sendiri: di dalam Manager, this.baseSalary bisa dipakai, tetapi mengakses baseSalary pada object Employee lain menghasilkan error CS1540.
Apa itu internal di C#?
internal membuat sebuah tipe atau member terlihat oleh semua kode di assembly yang sama (.dll atau .exe hasil compile dari project yang sama) dan tidak terlihat dari luar. Dengan cara inilah sebuah library menjauhkan class pembantunya dari API publiknya. [assembly: InternalsVisibleTo("MyLib.Tests")] membuat project test juga bisa melihatnya.
Bagaimana cara mengatasi "is inaccessible due to its protection level"?
Itu error CS0122: kode memakai member yang tidak boleh dilihatnya, paling sering field yang dibiarkan dengan default private. Kalau kode dari luar perlu membacanya, sediakan property atau method public; jangan sekadar menjadikan field-nya public. Kalau member itu berasal dari tipe di project lain, kemungkinan besar tipenya internal.