Skip to content
Theory · Classes and objects · lesson 5 of 11

Access modifiers

The door of a house has a combination lock. Any passer-by sees the buttons outside: entering the combination opens the door. The combination itself is kept inside the lock, and nobody on the street can read it or change it.

As long as every field of our classes is open, a house has no such protection. Let's add the door combination to House and a method that opens the door:

C#
var house = new House("1234");
Console.WriteLine(house.Code); // 1234
house.Code = "0000";
Console.WriteLine(house.Open("0000")); // True

class House
{
    public string Code;

    public House(string code) => Code = code;

    public bool Open(string code) => code == Code;
}

Let's see what is wrong here:

  1. new House("1234") puts the combination 1234 on the door.
  2. Any code in the program reads the combination through house.Code, and this line prints 1234.
  3. house.Code = "0000"; replaces the combination without knowing the old one.
  4. Now house.Open("0000") opens the door: there is a lock, but it is of no use.

The door combination should be visible only to the class House itself. C# has access modifiers for this.

Class members and modifiers

The fields, methods and constructors declared inside a class are called class members. An access modifier is the word before a class member that decides which code may use it. This theme needs two modifiers.

public

public makes an open member. Any code in the program can use it, including the top-level statements: house.Open("1234"). You make open whatever is used from outside the object. These are the lock's buttons.

An open member is a promise to all the other code. If a field is open, any line of the program may rely on it, and renaming or removing it later is hard.

private

private makes a closed member. Only the code of the class itself can use it: its methods and constructors. You make closed the data the class looks after itself. This is the combination inside the lock.

By the .NET convention, private fields are named with an underscore and a lowercase letter: _code. Let's rewrite the house:

C#
var house = new House("1234");
Console.WriteLine(house.Open("0000")); // False
Console.WriteLine(house.Open("1234")); // True

class House
{
    private string _code;

    public House(string code) => _code = code;

    public bool Open(string code) => code == _code;
}

The constructor and the method Open are code of the class, so they can use _code. But the line house._code in the top-level statements no longer compiles: error CS0122. There is no way to learn the combination from outside; you can only enter it on the buttons.

Here the lock analogy is imprecise. A private field is hidden from code outside the class, not from other houses. A method of the class House can read the _code of any House object, not only its own: the boundary is the class.

The default access

A member without a modifier is closed: string _code; means the same as private string _code;. That is why in C# you write public before every member that must be visible from outside. The code of the .NET platform itself still writes private explicitly, so the reader does not have to recall the rule.

Encapsulation

Private fields and public methods together give encapsulation: the class keeps its data itself and decides itself what can be done with it. Outside code uses only the open members and cannot spoil the data by going around the rules.

Suppose the door combination has to be changeable. Then the class gets an open method, for example ChangeCode(oldCode, newCode), which checks the old combination first. Replacing the combination without a check, as in the first example, is no longer possible.

Interviewers often ask: "What is encapsulation and why is it needed?" The answer has two parts:

  • an object's data is closed, and the work with it goes through the class's open methods;
  • so the class itself enforces the rules, and its insides can change without touching the code that uses it.

Common mistake

The method was not made open:

C#
var house = new House("1234");
Console.WriteLine(house.Open("1234")); // ✗

class House
{
    private string _code;

    public House(string code) => _code = code;

    bool Open(string code) => code == _code;
}
TEXT
error CS0122: 'House.Open(string)' is inaccessible due to its protection level

The program does not compile. Open has no modifier, so the method is closed and cannot be called from outside the class. The message says so directly: the method is inaccessible because of its protection level. Add public before bool Open.

Key points

  • An access modifier decides which code may use a class member: public means any code, private only the code of this class.
  • A member without a modifier is closed, as if private stood before it.
  • Encapsulation: the fields are closed and the work with them goes through open methods, so the class itself looks after its data.
  • Using a private member from outside the class does not compile: CS0122.