Access modifiers determine the accessibility of a type or type member, indicating which parts of a C# program can access those types and their members. By protecting types and members from unintended access, access modifiers contribute to achieving encapsulation.
Below is the list of all the access modifiers used in the C# language
Public
type or members with
private
access modifiers could be accessed by any code in the same assembly or another assembly referencing it.public
is the default access modifier for members of anenum
orinterface
.accessibility of public members is controlled by the access modifier of the type itself.
Code example
using System; namespace AccessModifierCode { class Employee { public int EmpId; public string Name; public Employee(int empid, string name) { EmpId = empid; Name = name; } } class Program { static void Main(string[] args) { // Creating object of the class Employee Employee E = new Employee(1, "Deepak"); Console.WriteLine("Emp Id: {0}", E.EmpId); Console.WriteLine("Name: {0}", E.Name); Console.WriteLine(); } } }
Private
members declared with
private
access modifier are accessible only within the containing type.private
access modifier is the most restrictive one.one can not declare a private class or struct directly inside a namespace.
private
is the default accessibility for members of a class or struct.public class Demo { string Name; // private }
using System; namespace AccessModifierCode { class Employee { public int EmpId; public string Name; private decimal Salary public Employee(int empid, string name, decimal salary) { EmpId = empid; Name = name; Salary = salary; } } class Program { static void Main(string[] args) { // Creating object of the class Employee Employee E = new Employee(1, "Deepak", 0); Console.WriteLine("Emp Id: {0}", E.EmpId); Console.WriteLine("Name: {0}", E.Name); Console.WriteLine("Salary: {0}", E.Salary); // Error : 'Employee.Salary is inaccessible due to its protection level' Console.WriteLine(); } } }
Internal
types or members declared with
internal
modifiers are accessible within the same assembly or friend assembly. Learn more about Friend assemblyinternal
is the default access modifier for class and struct types.
Protected
protected
type or members are accessible within the same class or derived class.
public class Shape {
protected int Width { get; set; }
protected int Height { get; set; }
}
public class Rectangle : Shape {
public Rectangle(int width, int height) {
Width = width;
Height = height;
}
}
protected internal
- Types or members declared with the
protected internal
modifier can be accessed only within the same assembly or in a derived class from another assembly.
private protected
- A member that is
private protected
is accessible only within the containing type, or subclasses that reside in the same assembly (making it less accessible than protected or internal alone).
Restrictions on Access Modifiers
Interfaces declared directly within a namespace can be
public
orinternal
and, just like classes and structs, interfaces default tointernal
access.Interface members are
public
by default.Enumeration members are always
public
, and no access modifiers can be applied.Delegates function similarly to classes and structs. When declared directly within a namespace, they have
internal
access by default, and when nested, they haveprivate
access.Derived classes and derived records can't have greater accessibility than their base types. You can't declare a public class
B
that derives from an internal classA
. If allowed, it would have the effect of makingA
public, because allprotected
orinternal
members ofA
are accessible from the derived class.
When overriding a base class function, accessibility must be identical to the over‐ ridden function.
class BaseClass {
protected virtual void Foo() {}
}
class Subclass1 : BaseClass {
protected override void Foo() {} // OK
}
class Subclass2 : BaseClass {
public override void Foo() {} // Error
}
Summary table
Caller's location | public | protected internal | protected | internal | private protected | private |
Within the class | ✔️️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
Derived class (same assembly) | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ❌ |
Non-derived class (same assembly) | ✔️ | ✔️ | ❌ | ✔️ | ❌ | ❌ |
Derived class (different assembly) | ✔️ | ✔️ | ✔️ | ❌ | ❌ | ❌ |
Non-derived class (different assembly) | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ |
(note: copied from MS learn)
So, that concludes our discussion on access modifiers. In this article, we covered the six access modifiers in C#: public, private, protected, internal, protected internal, and private protected. We learned about the purpose of each access modifier and their applications.
By employing the appropriate access modifier, we can ensure that our code is secure, user-friendly, and easy to maintain. Ultimately, this allows us to establish a clear and consistent structure for our code.
References and further reading