A Beginner's Guide to C# Access Modifiers: Learn the Basics

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
privateaccess modifiers could be accessed by any code in the same assembly or another assembly referencing it.publicis the default access modifier for members of anenumorinterface.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
privateaccess modifier are accessible only within the containing type.privateaccess modifier is the most restrictive one.one can not declare a private class or struct directly inside a namespace.

privateis 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
internalmodifiers are accessible within the same assembly or friend assembly. Learn more about Friend assemblyinternalis 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 internalmodifier can be accessed only within the same assembly or in a derived class from another assembly.
private protected
- A member that is
private protectedis 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
publicorinternaland, just like classes and structs, interfaces default tointernalaccess.Interface members are
publicby 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
internalaccess by default, and when nested, they haveprivateaccess.Derived classes and derived records can't have greater accessibility than their base types. You can't declare a public class
Bthat derives from an internal classA. If allowed, it would have the effect of makingApublic, because allprotectedorinternalmembers ofAare 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


