Access Modifiers - Controlling Visibility in C#

Vaibhav • September 10, 2025

In the previous article, we explored constructors - the special methods that initialize objects and ensure they start life in a valid state. Now that we understand how to create and configure objects, it’s time to learn how to control access to their members. This is where access modifiers come in.

Access modifiers define the visibility and accessibility of classes, fields, methods, properties, and other members. They are a key part of encapsulation, one of the core principles of object-oriented programming. By using access modifiers effectively, you can protect internal implementation details, expose only what’s necessary, and design clean, maintainable APIs.

What Are Access Modifiers?

Access modifiers are keywords that specify where a member can be accessed from. In C#, the most commonly used access modifiers are:

public      // Accessible from anywhere
private     // Accessible only within the containing class
protected   // Accessible within the containing class and derived classes
internal    // Accessible within the same assembly
protected internal // Accessible within the same assembly or from derived classes
private protected  // Accessible within the containing class or derived classes in the same assembly

These modifiers allow you to control the exposure of your class members and enforce boundaries between different parts of your codebase.

Using public and private

The two most commonly used access modifiers are public and private. A public member is accessible from anywhere, while a private member is accessible only within the class where it is declared.

class User
{
    private string password;
    public string Username;

    public void SetPassword(string pwd)
    {
        password = pwd;
    }
}

In this example, Username is public and can be accessed directly from outside the class. password is private and can only be accessed through the SetPassword method. This protects sensitive data and enforces encapsulation.

Understanding protected

The protected modifier allows access within the class and any class that inherits from it. This is useful when designing base classes that expose functionality to derived classes but not to external code.

class Animal
{
    protected string species;

    public void SetSpecies(string name)
    {
        species = name;
    }
}

class Dog : Animal
{
    public void PrintSpecies()
    {
        Console.WriteLine(species); // Accessible because it's protected
    }
}

Here, the Dog class inherits from Animal and can access the species field because it is protected. External code cannot access species directly.

Using internal for Assembly-Level Access

The internal modifier restricts access to the current assembly. This means the member is accessible from any class in the same project but not from other projects or assemblies.

internal class Logger
{
    internal void Log(string message)
    {
        Console.WriteLine(message);
    }
}

This is useful for hiding implementation details from external consumers while allowing full access within the same application or library.

Combining Modifiers: protected internal

The protected internal modifier allows access from the same assembly or from derived classes in other assemblies. It’s a combination of protected and internal.

class Base
{
    protected internal void Display()
    {
        Console.WriteLine("Visible to derived classes or same assembly");
    }
}

This modifier is useful when you want to expose functionality to trusted consumers (like derived classes or internal tools) but not to the general public.

Limiting Access with private protected

The private protected modifier restricts access to the containing class and derived classes within the same assembly. It’s more restrictive than protected internal.

class Base
{
    private protected void Configure()
    {
        Console.WriteLine("Accessible only in derived classes within the same assembly");
    }
}

This modifier is useful when you want to allow inheritance but keep the member hidden from external assemblies.

Access Modifiers for Classes

In C#, top-level classes can be public or internal. You cannot declare a top-level class as private or protected. Nested classes (classes declared inside another class) can use all access modifiers.

public class Outer
{
    private class Inner
    {
        public void SayHello()
        {
            Console.WriteLine("Hello from Inner class");
        }
    }
}

In this example, Inner is a private nested class and can only be accessed from within Outer.

Access Modifiers for Members

Fields, properties, methods, and constructors can use any access modifier. The default access modifier for class members is private if none is specified.

class Sample
{
    int number; // private by default

    public void Print()
    {
        Console.WriteLine(number);
    }
}

Here, number is private even though no modifier is specified. It can only be accessed within the Sample class.

Designing with Access Modifiers

Access modifiers are not just about hiding data - they are about designing clean and maintainable APIs. By exposing only what’s necessary, you reduce coupling, prevent misuse, and make your code easier to understand and evolve.

For example, you might expose a public method that performs a task, while keeping helper methods private. You might expose a read-only property to external code while allowing internal code to modify it.

class Account
{
    private decimal balance;

    public decimal Balance
    {
        get { return balance; }
    }

    public void Deposit(decimal amount)
    {
        if (amount > 0)
            balance += amount;
    }
}

In this example, the Balance property is read-only, and the Deposit method provides controlled access to modify the balance. This design enforces rules and protects the integrity of the object.

Summary

Access modifiers are a fundamental part of object-oriented programming in C#. They allow you to control the visibility and accessibility of classes and members, enforce encapsulation, and design clean APIs. The most commonly used modifiers are public, private, and protected, with additional options like internal, protected internal, and private protected for more nuanced control.

By using access modifiers thoughtfully, you can protect internal implementation details, expose only what’s necessary, and create code that is easier to maintain and extend. As you continue building applications in C#, access modifiers will help you enforce boundaries and write robust, well-structured code.

In the next article, we’ll explore Static Members - how to define members that belong to the class itself rather than to individual objects.