C# – Access modifiers

Access modifiers are used to hide class members (methods/properties/fields) from other code. When you define a class/method/property/field, you put an access modifier on it. In C#, there are four main access modifiers:

  • public: Everything can access it.
  • private: Only the class can access it.
  • protected: Only the class and its subclasses can access it.
  • internal: Everything in the assembly can access it.

Access modifiers are enforced at compile time. When you try to use a class member that you can’t access, you get the CS0122 <member name> is inaccessible due to its protection level compiler error.

I’ll show examples of the four main accessor modifiers.

Public access modifier

Using public on a class/class member makes it accessible from anywhere, including from other assemblies. A public class can contain public and non-public members. Here’s an example of a public class with a mix of private and public members.

public class Person
{
    public string Name { get; set; }

    private int count;
}
Code language: C# (cs)

Private access modifier

Using private makes a method/field/property-setter only accessible to the class where it’s defined. This is useful for a class’s internal state and methods you don’t want others to call. Here’s an example of a class with a mix of private and public members:

public class Person
{
    public string Name { get; set; }

    private int eatenAmount;
    public void Eat(int amount)
    {
        if (IsHungry())
        {
            eatenAmount += amount;
        }
    }

    private bool IsHungry()
    {
        //Implement complex hunger detection
        // -OR-
        // Always eat! :)
        return true; 
    }

}
Code language: C# (cs)

Here’s an example of attempting to use this class. Notice you get a compiler error if you try to use a private member (person.eatenAmount in this case):

//OK - Because Person is a public class
var person = new Person();

//CS0122: Inaccessible due to its protection level
person.eatenAmount++;

//OK - Because Eat() is public
person.Eat(10);
Code language: C# (cs)

It should be noted that access modifiers don’t completely block access. You can use reflection to access anything, including private members, but that should only be done as a last resort.

Property with a private setter

Usually you won’t want to make properties private. Instead, it’s common to make a public property with a private setter. This essentially makes the property read-only from outside the class.

Here’s an example. Let’s say you want to modify the Person class (shown above), so that the eatenAmount field can be read by anyone (but not modified). To do that, make it a public property with a private setter:

public class Person
{
    public int EatenAmount
    {
        get;
        private set;
    }
	//rest of class
}
Code language: C# (cs)

Now this read-only property can be read from outside (but not modified because the setter is private):

var person = new Person();

person.Eat(10);

//OK - because EatenAmount has a public getter
Console.WriteLine($"Person eaten amount: {person.EatenAmount}");

//CS0122: Inaccessible due to its protection level
person.EatenAmount++;
Code language: C# (cs)

Protected access modifier

Use protected to make a class member only accessible to the class and its subclasses. This is useful when you have an abstract base class and want to make a “private” member accessible to its subclasses.

Here’s an example of using protected:

public abstract class PersonBase
{
    protected int status;
    public abstract void DoWork();
}

public class Coder : PersonBase
{
    public override void DoWork()
    {
        status = 1;
    }
}
Code language: C# (cs)

Notice that the subclass (Coder) can access the protected PersonBase.status field.

At the same time, the protected field is not accessible from outside the class. Here’s an example to show this:

var person = new Coder();

//CS0122: Inaccessible due to its protection level
if (person.status == 1)
{

   //...
}
Code language: C# (cs)

Internal access modifier

Use internal to make a class/method/property/field accessible to all code in the assembly where the class is declared. Here’s an example:

internal class Coder
{
    internal string Language { get; set; }
}
Code language: C# (cs)

Code outside the assembly can’t access the internal class or internal members:

//CS0122 - Inaccessible due to its protection level
var person = new Coder();
person.Language = "C#";
Code language: C# (cs)