C# > Object-Oriented Programming (OOP) > Encapsulation > Access Modifiers for Members

Encapsulation with Access Modifiers in C#

This code demonstrates encapsulation using access modifiers in C#. Encapsulation is a fundamental principle of object-oriented programming (OOP) that involves bundling the data (attributes) and methods (functions) that operate on that data within a single unit, known as a class. Access modifiers control the visibility and accessibility of class members.

Code Example

This example demonstrates a `BankAccount` class. The `accountNumber` and `balance` fields are declared as `private`. This means they can only be accessed from within the `BankAccount` class itself. Public properties `AccountNumber` and `Balance` provide controlled access to these fields. The `Deposit` and `Withdraw` methods provide controlled ways to modify the balance. Trying to access `balance` directly from outside the class will result in a compile-time error, enforcing encapsulation. This approach protects the internal state of the object and prevents unauthorized modifications.

using System;

public class BankAccount
{
    private string accountNumber;
    private decimal balance;

    public BankAccount(string accountNumber, decimal initialBalance)
    {
        this.accountNumber = accountNumber;
        this.balance = initialBalance;
    }

    public string AccountNumber
    {
        get { return accountNumber; }
    }

    public decimal Balance
    {
        get { return balance; }
    }

    public void Deposit(decimal amount)
    {
        if (amount > 0)
        {
            balance += amount;
            Console.WriteLine($"Deposited {amount:C}. New balance: {balance:C}");
        }
        else
        {
            Console.WriteLine("Deposit amount must be positive.");
        }
    }

    public void Withdraw(decimal amount)
    {
        if (amount > 0 && balance >= amount)
        {
            balance -= amount;
            Console.WriteLine($"Withdrawn {amount:C}. New balance: {balance:C}");
        }
        else
        {
            Console.WriteLine("Insufficient funds or invalid withdrawal amount.");
        }
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        BankAccount myAccount = new BankAccount("1234567890", 1000);

        Console.WriteLine($"Account Number: {myAccount.AccountNumber}");
        Console.WriteLine($"Initial Balance: {myAccount.Balance:C}");

        myAccount.Deposit(500);
        myAccount.Withdraw(200);

        // Trying to directly access the private balance would result in a compilation error.
        // Console.WriteLine(myAccount.balance); // This line would cause an error.

        Console.ReadKey();
    }
}

Concepts Behind the Snippet

The key concepts demonstrated here are:

  • Encapsulation: Bundling data (attributes) and methods (functions) that operate on that data within a single unit (class).
  • Access Modifiers: Keywords that control the accessibility of class members. Common access modifiers include:
    • `private`: Accessible only within the declaring class.
    • `public`: Accessible from anywhere.
    • `protected`: Accessible within the declaring class and its derived classes.
    • `internal`: Accessible within the same assembly.
    • `protected internal`: Accessible within the same assembly or from derived classes in another assembly.
  • Properties: Provide controlled access to class fields (getters and setters).

Real-Life Use Case

Consider a system managing employee data. Sensitive information like salary and social security number should be encapsulated. You could use private fields for these attributes and provide controlled access through methods or properties. For example, only authorized personnel (e.g., HR) should be able to view or modify the salary. Encapsulation ensures data integrity and security.

Best Practices

  • Favor `private` fields and provide access through properties.
  • Use access modifiers to restrict access to members that should not be directly modified from outside the class.
  • Consider using auto-implemented properties for simple properties with no additional logic. For example: `public string Name { get; set; }`
  • Think carefully about the visibility requirements of each member when designing a class.

Interview Tip

When discussing encapsulation, emphasize that it's not just about hiding data. It's about controlling access and preventing direct manipulation of internal state, which leads to more robust and maintainable code. Explain how access modifiers and properties play a crucial role in achieving encapsulation.

When to Use Them

Use encapsulation whenever you want to protect the internal state of an object and control how it's accessed and modified. This is especially important for complex objects with sensitive data or when you want to enforce specific business rules.

Memory Footprint

Encapsulation itself doesn't directly affect memory footprint. The memory footprint of a class is determined by the data members it contains (fields). Access modifiers don't change the amount of memory allocated to the object. They only control access to that memory.

Alternatives

While access modifiers are the primary way to enforce encapsulation, other techniques can contribute to data protection:

  • Readonly Fields: Used to ensure that a field can only be assigned a value once (typically in the constructor).
  • Immutable Objects: Objects whose state cannot be changed after creation.

Pros

  • Data Hiding: Prevents direct access to internal data.
  • Code Maintainability: Changes to the internal implementation of a class are less likely to affect other parts of the application.
  • Reduced Complexity: Simplifies the interface of a class, making it easier to understand and use.
  • Increased Security: Protects sensitive data from unauthorized access.

Cons

  • Increased Complexity: Can add some complexity to the design of a class.
  • Potential Performance Overhead: Using properties instead of direct field access can introduce a small performance overhead, although this is often negligible.

FAQ

  • Why use properties instead of directly accessing public fields?

    Properties provide a level of indirection that allows you to add logic to the getter and setter. For example, you can perform validation, raise events, or calculate a derived value when the property is accessed or modified.
  • What is the difference between `private` and `protected`?

    `private` members are only accessible within the class where they are declared. `protected` members are accessible within the class where they are declared and in any derived classes, even if those derived classes are in a different assembly.