Skip to content

Access Modifiers

Access modifiers control the visibility and accessibility of types and their members (fields, properties, methods, etc.). They determine which parts of your codebase can see and interact with a given member, making them a key tool for encapsulation.

.NET provides six access modifiers: public, private, protected, internal, protected internal, and private protected.

For additional reference, see the Microsoft documentation on access modifiers.


public

Accessible from anywhere — same class, same assembly, or any external assembly.

public class Car
{
    public string Make { get; set; }
}

// Accessible from anywhere
var car = new Car();
car.Make = "Toyota";

private

Accessible only within the class or struct it is declared in. This is the default for class members if no modifier is specified.

public class BankAccount
{
    private decimal _balance;

    public void Deposit(decimal amount) => _balance += amount;
    public decimal GetBalance() => _balance;
}

// _balance is not accessible here
var account = new BankAccount();
account.Deposit(100);

protected

Accessible within the class it is declared in and by any class that inherits from it, but not from outside those classes.

public class Animal
{
    protected string Name { get; set; }
}

public class Dog : Animal
{
    public void SetName(string name) => Name = name; // OK — inherited
}

// Not accessible here
var dog = new Dog();
// dog.Name = "Rex"; // Error

internal

Accessible from anywhere within the same assembly, but not from other assemblies. Useful for members that should be shared across your project but hidden from external consumers.

// In MyApp.dll
internal class ConfigLoader
{
    internal string LoadConfig() => "config data";
}

// Accessible anywhere else inside MyApp.dll
var loader = new ConfigLoader();
loader.LoadConfig();

// Not accessible from a different assembly (e.g. a consumer NuGet package)

protected internal

Accessible within the same assembly or from a derived class in any assembly. It is the union of protected and internal.

public class Logger
{
    protected internal void Log(string message) =>
        Console.WriteLine(message);
}

// Accessible from the same assembly
var logger = new Logger();
logger.Log("Hello");

// Also accessible from a subclass in a different assembly
public class FileLogger : Logger
{
    public void LogToFile(string message) => Log(message); // OK
}

private protected

Accessible only within the same class or a derived class, and only if both are in the same assembly. It is the intersection of protected and internal.

public class Repository
{
    private protected void ExecuteQuery(string sql)
    {
        // Internal implementation
    }
}

// Only a subclass in the same assembly can access this
public class UserRepository : Repository
{
    public void GetUsers()
    {
        ExecuteQuery("SELECT * FROM Users"); // OK — same assembly + derived
    }
}

// A subclass in a different assembly cannot access ExecuteQuery