Access Modifiers
Access modifiers in C# define the visibility and accessibility of classes, methods, and variables within a program. They help in encapsulation, ensuring that code components are properly restricted or exposed based on design requirements.
Why Use Access Modifiers?
- To control access levels to class members and prevent unintended modifications.
- To enforce data hiding and protect sensitive information.
- To establish modular and maintainable code structures.
Public
The public access modifier allows members to be accessible from anywhere within the program, including different classes and assemblies.
Key Characteristics:
- Members marked as
publichave no restrictions on access. - Suitable for components that are meant to be widely accessible, such as utility methods or global constants.
- Provides the highest level of accessibility.
Example:
public class Car
{
public string Model; // Public field accessible from anywhere
public void Drive() // Public method accessible from anywhere
{
Console.WriteLine("Driving...");
}
}
Car myCar = new Car();
myCar.Model = "Toyota"; // Accessible from outside the Car class
myCar.Drive(); // Accessible from outside the Car class
Explanation:
- The
Modelproperty andDrive()method can be accessed freely by other classes. - Useful when designing libraries or APIs that need to provide public functionalities.
Metaphor:
It's like a public park where everyone can enter and enjoy the facilities without any restrictions.
Common Use Cases:
- Public API endpoints in libraries.
- Global utility classes and helper functions.
- Configuration settings that should be accessible across the application.
Private
The private access modifier restricts access to members only within the same class, making them inaccessible from outside the class.
Key Characteristics:
- Members marked as
privatecan only be accessed inside the class where they are declared. - Ensures data encapsulation, preventing direct access and modification from external code.
- Provides the highest level of data protection.
Example:
public class BankAccount
{
private decimal balance; // Private field, accessible only within the class
public void Deposit(decimal amount)
{
balance += amount; // Accessible inside the class
}
public decimal GetBalance()
{
return balance; // Exposing balance through a public method
}
}
BankAccount account = new BankAccount();
account.Deposit(500);
// account.balance = 1000; // Error: balance is private and cannot be accessed directly
Console.WriteLine(account.GetBalance()); // Accessing balance through a public method
Explanation:
- The
balancefield is private, meaning it cannot be accessed directly from outside the class. - Access is allowed only through the public methods
Deposit()andGetBalance().
Metaphor:
It's like a personal safe in your home—only you can access its contents, and others must go through you to retrieve anything.
Common Use Cases:
- Storing sensitive data such as passwords or account balances.
- Internal helper methods that shouldn't be exposed outside the class.
- Implementing encapsulation to avoid unintended modifications.
Protected
The protected access modifier allows members to be accessible within the same class and in derived (child) classes, but not from outside those classes.
Key Characteristics:
- Members marked as
protectedcan be accessed within their class and by subclasses (derived classes). - Supports inheritance, allowing child classes to reuse and extend functionality.
- Prevents access from outside the class hierarchy, maintaining a level of encapsulation.
Example:
public class Animal
{
protected string Species; // Protected field accessible in derived classes (Animal -> ...)
protected void SetSpecies(string species)
{
Species = species; // Accessible within the base class
}
}
public class Dog : Animal
{
public void Identify()
{
SetSpecies("Canine"); // Accessible from the derived class
Console.WriteLine($"This animal is a {Species}");
}
}
Dog myDog = new Dog();
myDog.Identify();
// myDog.SetSpecies("Canine"); // Error: protected method cannot be accessed directly
Explanation:
- The
Speciesfield andSetSpecies()method are protected, meaning they can be accessed within theAnimalclass and its derived classDog, but not from outside. - Useful when designing a class hierarchy where base class data needs to be shared with subclasses.
Metaphor:
It's like family secrets—they are known within the family (class and subclasses) but hidden from outsiders.
Common Use Cases:
- Allowing child classes to access and modify parent class properties safely.
- Implementing core functionality in a base class and exposing it only to subclasses.
- Providing extensibility while maintaining encapsulation from unrelated classes.
The difference between private and protected
The private access modifier restricts access to members within the same class, while the protected access modifier allows access within the same class and its derived classes.
public class Parent
{
private int privateField;
protected int protectedField;
public void AccessFields()
{
privateField = 10; // Accessible within the same class
protectedField = 20; // Accessible within the same class
}
}
public class Child : Parent
{
public void AccessFields()
{
// privateField = 10; // Error: private field is not accessible in derived class
protectedField = 20; // Accessible in derived class
}
}
Parent child = new Child();
// child.privateField = 10; // Error: private field is not accessible in derived class
// child.protectedField = 20; // Error: protected field is not accessible outside the class
Internal
The internal access modifier allows members to be accessible only within the same assembly, meaning they can be accessed by any code within the same project but not from another assembly.
TODO: Add a note about assembly
So, basically, assembly is a .dll or .exe file. We got it from the compilation of the code inside the certain project.
Key Characteristics:
- Members marked as
internalare restricted to the same assembly (i.e., project). - Useful for dividing functionality across multiple classes within a project while keeping it hidden from external assemblies.
- Provides a balance between accessibility and encapsulation.
Example.
Project A (Assembly 1):
internal class Logger
{
internal void Log(string message)
{
Console.WriteLine($"Log: {message}");
}
}
// Accessible within the same assembly
Logger logger = new Logger();
logger.Log("Logging internal data.");
Project B (Assembly 2):
// Error: Logger is not accessible from a different assembly
Logger logger = new Logger();
logger.Log("Logging internal data.");
Explanation:
- The
Loggerclass and its methodLog()are accessible from anywhere within the same assembly, but trying to access them from a different assembly will result in an error. - This is commonly used when building libraries or large projects where internal components shouldn't be exposed to consumers.
Metaphor:
It's like company documents — accessible to all employees within the organization, but hidden from outsiders.
Common Use Cases:
- Hiding implementation details that are not intended to be used outside of the project.
- Creating utility classes or helper functions specific to the project.
- Managing internal business logic that should not be exposed to external consumers.
Protected Internal
The protected internal access modifier allows members to be accessible within the same assembly and to derived (child) classes outside the assembly. This means the member can be accessed by any code within the same project, and also by subclasses in different assemblies.
Key Characteristics:
- Members marked as
protected internalare accessible inside the same assembly, similar tointernalmembers. - They can also be accessed outside the assembly, but only through inheritance.
- Provides a combination of protected (accessible to derived classes) and internal (restricted to the same assembly) functionality.
Protected + Internal = Protected Internal. Simple math!
Example.
Project A (Assembly 1):
public class BaseClass
{
protected internal void ShowMessage()
{
Console.WriteLine("Protected Internal Access");
}
}
public class DerivedClass : BaseClass
{
public void Display()
{
ShowMessage(); // Accessible in derived class within the same assembly
}
}
// Accessible within the same assembly
BaseClass obj = new BaseClass();
obj.ShowMessage(); // Allowed within the same assembly
Project B (Assembly 2):
public class AnotherDerivedClass : BaseClass
{
public void Test()
{
ShowMessage(); // Accessible because of inheritance
}
}
// BaseClass obj = new BaseClass();
obj.ShowMessage(); // Error: Cannot access without inheritance
Explanation:
- The
ShowMessage()method is accessible within the same assembly directly. - In a different assembly, it is only accessible through inheritance (in derived classes).
- Direct instantiation in another assembly without inheritance is not allowed, ensuring encapsulation.
Metaphor:
It's like family privileges within an organization— family members can access certain resources outside of the company, but outsiders can't access them unless they are part of the family.
Common Use Cases:
- Allowing derived classes in external projects to access specific members while keeping them hidden from unrelated classes.
- Providing extensibility while maintaining a level of internal control.
- Useful in frameworks where certain methods should be extendable but not publicly available.
Private Protected
The private protected access modifier allows members to be accessible within the same assembly but ONLY by derived (child) classes, restricting access even further compared to protected internal.
Key Characteristics:
- Members marked as
private protectedcan be accessed only within the same assembly and only by derived classes. - It provides the most restrictive combination of
protectedandinternalby limiting access to subclasses within the same project. - Not accessible from outside the assembly, even through inheritance.
Example.
Project A (Assembly 1):
public class BaseClass
{
private protected void Display()
{
Console.WriteLine("Private Protected Access");
}
}
public class DerivedClass : BaseClass
{
public void Show()
{
Display(); // Accessible in derived class within the same assembly
}
}
BaseClass obj = new BaseClass();
obj.Display(); // Error: Cannot access from outside the class hierarchy
Project B (Assembly 2):
public class AnotherDerivedClass : BaseClass
{
public void Test()
{
Display(); // Error: Cannot access from a derived class in another assembly
}
}
Explanation:
- The
Display()method is accessible within the same assembly in derived classes. - It is not accessible in derived classes outside the assembly.
- Even direct instantiation and access within the same assembly outside of inheritance is not allowed.
Metaphor:
It's like family secrets shared only within the household, accessible to close family members but not to extended family or outsiders.
Common Use Cases:
- Providing internal extension capabilities within the same project while preventing unintended access from external code.
- Ensuring stricter encapsulation compared to
protected internalby confining access within the assembly. - Useful in large projects to limit access to critical internal functionalities only for sub-classing within the same module.
Sealed Keyword
The sealed keyword is used to prevent a class from being inherited by other classes. When a class is marked as sealed, it cannot be used as a base class for other classes.
Example:
public sealed class FinalClass
{
public void Display()
{
Console.WriteLine("This is a sealed class");
}
}
// Error: Cannot inherit from a sealed class
public class DerivedClass : FinalClass
{
// Code here
}