Access modifiers
In C#, access modifiers are used to control the visibility and accessibility of members (fields, methods, properties, etc.) in a class or struct. Access modifiers are essential to achieving two key Object-Oriented Programming (OOP) concepts: abstraction and encapsulation.
In C#, there are five access modifiers that can be used to control the visibility of members. These are:
- Public: Public members are visible to all code within the assembly and other assemblies that reference it.
- Private: Private members are only visible to code within the same class or struct.
- Protected: Protected members are visible to code within the same class or struct and any derived classes.
- Internal: Internal members are visible to all code within the same assembly, but not to code in other assemblies.
- Protected internal: Protected internal members are visible to code within the same assembly and any derived classes, regardless of the assembly they are in.
To redraw
Why do we need them?
Object-Oriented Programming (OOP) is a programming paradigm that is based on the concept of objects, which can contain data and behavior. OOP is widely used in software development because it provides a way to organize code, make it more reusable, and easier to maintain.
There are four primary OOP paradigms:
- Abstraction
- Encapsulation
- Inheritance
- Polymorphism
Today we are going to talk about two of them: Abstraction and Encapsulation, as they are implemented in C# using access modifiers.
Abstraction
Abstraction is the process of hiding the implementation details of an object and showing only the essential features to the outside world. Access modifiers help achieve abstraction by controlling the visibility of members. By hiding certain members from the outside world, the object’s implementation details are abstracted away, and only the essential features are exposed.
For example, you might be familiar with the Console class and have already used some of its functionality.
Like WriteLine, for example:
Console.WriteLine("Hello, world!");
We, as consumers, know that this method can print a string to a console and adds a new line at the end. However, we don’t see or know how it is implemented. It is the proper abstraction.
Encapsulation
Encapsulation, on the other hand, is the process of bundling data and behavior inside an object and restricting direct access to the data from the outside world. Access modifiers play a crucial role in encapsulation by controlling access to members. By using access modifiers like private, the data inside the object is protected from direct modification by external code, and only the object’s behavior can change it.
Let’s take a look at an example of a BankAccount class:
public class BankAccount { public double balance; public void deposit(double amount) { balance += amount; } public void withdraw(double amount) { if (balance >= amount) { balance -= amount; } } public double getBalance() { return balance; } }
Here you see a very insecure implementation of this kind of class. Here we have both deposit and withdrawal methods. However, the balance attribute is public and accessible to the outside world and anyone can change it at a certain point to any number.
The right implementation would be:
public class BankAccount { private double balance; public void deposit(double amount) { balance += amount; } public void withdraw(double amount) { if (balance >= amount) { balance -= amount; } } public double getBalance() { return balance; } }
In this case, only the BanckAccount class has access to the balance and can control all changes to avoid miscalculations, bugs, and data corruption.