Access Modifiers in C# define how accessible a class, method, field, property, or other class members are to other program parts. They are essential for implementing encapsulation, one of the key principles of Object-Oriented Programming (OOP).
The public access modifier in C# specifies that a member (such as a field, property, method, or class) is accessible from any other part of the program, without restrictions. When a member is declared public, it can be accessed directly by code outside of the class or assembly in which it is defined.
Example
class Person
{
public string Name; // Can be accessed from outside the class
}
class Program
{
static void Main()
{
Person person = new Person();
person.Name = "Mayooran"; // Accessing public field
Console.WriteLine(person.Name);
}
}
This code demonstrates a simple class named Person with a single public field, Name, which can be accessed and modified outside the class. In the Program class, the Main method creates an instance of the Person class and assigns the Name field the value "Mayooran". It then uses the Console.WriteLine method to print the value of the Name field to the console. This demonstrates how to declare a public field, instantiate a class, and interact with its members. However, exposing fields to the public is generally discouraged in favor of using properties for better encapsulation and control.

Image 01: Person Can be accessed from outside the class
The private access modifier in C# restricts access to members of a class to the class itself. This is the most restrictive access level, ensuring that the member can only be accessed and used within the class where it is defined.
Example
class BankAccount
{
private decimal balance; // Private field
public void Deposit(decimal amount)
{
if (amount > 0)
balance += amount; // Accessible within the class
}
public decimal GetBalance() => balance; // Exposes value securely
}
class Program
{
static void Main()
{
BankAccount account = new BankAccount();
account.Deposit(1000); // Access public method
// Console.WriteLine(account.balance); // Error: balance is private
Console.WriteLine(account.GetBalance());
}
}
This code demonstrates a simple implementation of encapsulation in a BankAccount class. The class includes a private field, balance, which is used to store the account balance securely. Since the balance is marked as private, it cannot be accessed or modified directly from outside the class. Instead, the Deposit method is provided to safely add a specified amount to the balance, with a condition ensuring only positive values are accepted. To retrieve the balance, the class exposes a GetBalance method, which returns the value securely without allowing direct manipulation.
In the Program class, the Main method creates an instance of the BankAccount class and uses the Deposit method to add money to the account. The attempt to access the balance field directly would result in an error, illustrating the protection provided by the private access modifier. Finally, the GetBalance method is called to display the current balance. This design adheres to object-oriented programming principles by encapsulating data and providing controlled access through public methods.
Such encapsulation ensures that the class's internal state remains consistent and minimizes the risk of unintended modifications. It also allows for additional logic, such as validation, to be implemented within the class methods without exposing the underlying fields to the calling code. This approach makes the BankAccount class secure and easier to maintain.

Image 02: Balance cannot be accessed from outside the class (Console.WriteLine(account.balance); // Error: balance is private)
The protected access modifier in C# allows a class member to be accessible only within its class and by derived (child) classes. It strikes a balance between encapsulation and flexibility, enabling derived classes to reuse and extend the functionality of the base class.
Example
class Animal
{
protected void Eat() => Console.WriteLine("Eating...");
}
class Dog : Animal
{
public void BarkAndEat()
{
Console.WriteLine("Barking...");
Eat(); // Accessible because Dog inherits Animal
}
}
class Program
{
static void Main()
{
Dog dog = new Dog();
dog.BarkAndEat();
// dog.Eat(); // Error: Eat is protected
}
}
This code demonstrates the use of the protected access modifier, which allows base class members to be accessed by derived classes but not by external code. The Animal class defines a protected field, Species, and a protected method, DisplaySpecies. The Species field is initialized through the Animal constructor.
The Dog class inherits from Animal and uses the base class constructor to set the Species field to "Dog." It also calls the DisplaySpecies method from the base class to display the species of the animal. The Speak method extends the functionality by adding a message specific to the Dog class.
In the Main method, an instance of the Dog class is created, and its Speak method is called, which successfully uses the protected members of the Animal class. Direct access to the Species field or DisplaySpecies method from the Main method is not allowed, ensuring encapsulation within the class hierarchy. This illustrates how protected members enable controlled reuse and extension of base class functionality in derived classes.

Image 03: The Eat method cannot be accessed from outside the class dog.Eat(); // Error: Eat is protected
The internal access modifier in C# specifies that a member or type is accessible only within the same assembly. It provides a way to share functionality across multiple classes and files within an assembly while keeping it hidden from external assemblies.
Example
File 01. MyLibrary
namespace MyLibrary
{
internal class InternalHelper
{
internal string GetInternalMessage()
{
return "This is an internal message from MyLibrary.";
}
}
public class PublicAPI
{
public string FetchMessage()
{
InternalHelper helper = new InternalHelper();
return helper.GetInternalMessage(); // Internal member accessed within the same assembly
}
}
class Program
{
static void Main(string[] args)
{
PublicAPI api = new PublicAPI();
string message = api.FetchMessage();
Console.WriteLine(message);
}
}
}
File 02. Access_Modifiers_C_
using MyLibrary;
namespace Access_Modifiers_C_
{
class Program
{
static void Main()
{
// Attempting to access the internal class directly will result in an error
// InternalHelper helper = new InternalHelper(); // Error: InternalHelper is inaccessible
PublicAPI api = new PublicAPI();
Console.WriteLine(api.FetchMessage()); // Access internal functionality through the public API
}
}
}
This code demonstrates,

Image 04.1: MyLibrary solution has PublicApi

Image 04.2: PublicApi object access from MyLibrary
The protected internal access modifier in C# is a combination of two access levels: protected and internal. It allows members to be accessed either by derived classes or within the same assembly. This provides a flexible access scope that balances encapsulation and extensibility.
Example
class Vehicle
{
protected internal void StartEngine() => Console.WriteLine("Engine started!");
}
class Car : Vehicle
{
public void Drive() => StartEngine(); // Accessible due to inheritance
}
class Program
{
static void Main()
{
Vehicle vehicle = new Vehicle();
vehicle.StartEngine(); // Accessible in the same assembly
}
}
This code demonstrates the use of the protected internal access modifier, allowing the StartEngine method in the Vehicle class to be accessed within the same assembly or by derived classes. The StartEngine method outputs a message indicating that the engine has started.
The Car class inherits from Vehicle and uses the StartEngine method in its Drive method. This is possible because protected internal allows access to inherited members within derived classes, even when the derived class is in a different assembly.
In the Main method, an instance of the Vehicle class is created, and its StartEngine method is called directly. This is allowed because the method is accessible within the same assembly due to the internal portion of protected internal.
If the StartEngine method were accessed from a non-derived class in a different assembly, it would result in a compilation error. This restriction enforces encapsulation while still allowing flexibility for inheritance and same-assembly access.
This code illustrates how protected internal provides controlled access for both class hierarchies and internal usage, making it useful in scenarios where shared and extensible functionality is needed.

Image 05: PublicApi object access from MyLibrary
The private protected access modifier in C# is a combination of two access levels: private and protected. It restricts access to members within the same class, derived classes, and the same assembly. This provides tighter control compared to protected internal.
Example
class BaseClass
{
private protected void Display() => Console.WriteLine("Private Protected method!");
}
class DerivedClass : BaseClass
{
public void CallDisplay() => Display(); // Accessible in derived class
}
class Program
{
static void Main()
{
// BaseClass baseObj = new BaseClass();
// baseObj.Display(); // Error: Not accessible outside BaseClass or its derived classes
}
}
This code demonstrates the use of the private protected access modifier, which restricts member access to the containing class (BaseClass) and derived classes within the same assembly. The Display method in the BaseClass is marked as private protected, so it can only be accessed by derived classes like DerivedClass within the same assembly.
The derived class inherits from BaseClass and contains the CallDisplay method, which internally calls the Display method. This is allowed because the private protected modifier grants access to members within derived classes in the same assembly.
In the Main method, an attempt to directly access the Display method through an instance of BaseClass would result in a compilation error. This is because private protected members cannot be accessed outside the class hierarchy, even within the same assembly.
This setup ensures that sensitive functionality, such as the Display method, remains hidden from external access but is still usable by inheriting classes for internal purposes. The private protected modifier thus combines strict encapsulation with controlled extensibility.
Overall, this code highlights how the private protected access level enforces both class-level privacy and limited inheritance access within the same assembly.

Image 06: Private protected access modifier

Access modifiers are a fundamental feature of C# for managing access and ensuring that code is secure, maintainable, and scalable. By using them effectively, developers can enforce proper boundaries, reduce bugs, and design more robust and modular systems. Always choose the most restrictive modifier that meets your requirements to ensure good encapsulation and maintainability.