Understanding C# Access Modifiers: Public, Private, Protected, Internal, and More
Understanding C# Access Modifiers
This guide explains how the various C# access modifiers—public, private, protected, internal, protected internal, and private protected—control visibility of types and members. Real‑world code examples illustrate each modifier’s effect.
In C#, access modifiers determine who can read or write fields, call methods, or instantiate types. For instance:
class Student {
public string name;
private int num;
}
Here, name is visible everywhere, whereas num is confined to the Student class.
Types of Access Modifiers
- public
- private
- protected
- internal
- protected internal
- private protected
1. Public Access Modifier
Marking a type or member as public makes it accessible from any code that can reference the assembly.
using System;
namespace MyApplication {
class Student {
public string name = "Sheeran";
public void Print() {
Console.WriteLine("Hello from Student class");
}
}
class Program {
static void Main(string[] args) {
Student student1 = new Student();
Console.WriteLine("Name: " + student1.name);
student1.Print();
Console.ReadLine();
}
}
}
Output
Name: Sheeran Hello from Student class
Because both the field and method are public, the Program class can freely access them.
Tip: The object student1 is used to access the members of Student. Learn more about C# class and objects.
2. Private Access Modifier
A private member is visible only within its declaring class or struct. Outside code, such members trigger compile‑time errors.
using System;
namespace MyApplication {
class Student {
private string name = "Sheeran";
private void Print() {
Console.WriteLine("Hello from Student class");
}
}
class Program {
static void Main(string[] args) {
Student student1 = new Student();
Console.WriteLine("Name: " + student1.name);
student1.Print();
Console.ReadLine();
}
}
}
Attempting to access name or Print from Program results in:
CS0122 'Student.name' is inaccessible due to its protection level
CS0122 'Student.Print()' is inaccessible due to its protection level
3. Protected Access Modifier
Members marked protected are accessible within their own class and any derived classes, regardless of assembly.
using System;
namespace MyApplication {
class Student {
protected string name = "Sheeran";
}
class Program : Student {
static void Main(string[] args) {
Program program = new Program();
Console.WriteLine("Name: " + program.name);
Console.ReadLine();
}
}
}
Output
Name: Sheeran
Here, Program inherits from Student, enabling it to access the protected name field.
4. Internal Access Modifier
An internal member is visible only within the same assembly—a logical unit of compiled code. Assemblies are created by the compiler when you build a project.
Within a single assembly:
using System;
namespace Assembly {
class Student {
internal string name = "Sheeran";
}
class Program {
static void Main(string[] args) {
Student theStudent = new Student();
Console.WriteLine("Name: " + theStudent.name);
Console.ReadLine();
}
}
}
Output
Name: Sheeran
When the same assembly tries to access the field, it behaves like public because internal members are shared across the entire assembly.
In a different assembly, the field is inaccessible:
// Assembly1
using System;
namespace Assembly1 {
public class StudentName {
internal string name = "Sheeran";
}
}
// Assembly2
using System;
using Assembly1;
namespace Assembly2 {
class Program {
static void Main(string[] args) {
StudentName student = new StudentName();
Console.Write(student.name); // CS0122
Console.ReadLine();
}
}
}
Attempting to compile Assembly2 produces:
CS0122 'StudentName.name' is inaccessible due to its protection level
5. Protected Internal Access Modifier
The protected internal combination allows access from the same assembly or from derived types in other assemblies.
// Assembly1
using System;
namespace Assembly1 {
public class Greet {
protected internal string msg = "Hello";
}
}
// Assembly2
using System;
using Assembly1;
namespace Assembly2 {
class Program : Greet {
static void Main(string[] args) {
Program greet = new Program();
Console.Write(greet.msg);
Console.ReadLine();
}
}
}
Output
Hello
6. Private Protected Access Modifier
Introduced in C# 7.2, private protected restricts visibility to the declaring class and its derived classes within the same assembly.
// Assembly1
using System;
namespace Assembly1 {
public class StudentName {
private protected string name = "Sheeran";
}
class Program1 : StudentName {
static void Main(string[] args) {
Program1 student = new Program1();
Console.Write(student.name);
Console.ReadLine();
}
}
}
// Assembly2
using System;
using Assembly1;
namespace Assembly2 {
class Program : StudentName {
static void Main(string[] args) {
Program student = new Program();
Console.Write(student.name); // CS0122
Console.ReadLine();
}
}
}
Access from Assembly2 fails because the member is not exposed beyond its assembly, even in derived types.
Note: While types (classes, interfaces, etc.) can use public and internal, all other modifiers apply only to members.
C Language
- C# Static Keyword: Mastering Static Variables, Methods, and Classes
- Mastering C# Inheritance: Concepts, Types, and Practical Code
- Understanding C# Nested Classes: Definition, Usage, and Inheritance
- Master C++ Inheritance: Build Powerful Classes with Reusable Code
- Understanding Java Access Modifiers: Types, Rules, and Practical Examples
- Understanding C# Access Modifiers (Specifiers) with Practical Examples
- Java Modifiers Explained: Types, Usage, and Best Practices
- Master C# Encapsulation: Safeguarding Code and Boosting Design
- Mastering C# Inheritance: Build Reusable, Maintainable Code
- C# Polymorphism: Static vs Dynamic Binding Explained