Start learning free

LESSON 184 OF 347 · OBJECT-ORIENTED PROGRAMMING

Access Modifiers in C#: public, private and Encapsulation

Lesson Read the full explanation

TL ; DR:

  • An access modifier controls who can see a member of a class. The two you'll use most are public (anyone) and private (only this class).


  • Make data private so callers can't break invariants by writing to it. Expose what they need through public methods:

    class Dog {
        private string name;        // hidden from outside
    
        public Dog(string name) {   // anyone can construct
            this.name = name;
        }
    
        public string GetName() {   // controlled read access
            return name;
        }
    }
    

  • Outside the class, rex.name is a compile error. Use rex.GetName() instead.



Full lesson:

So far every field we wrote was public — anyone could read or write it. That's convenient, but it leaks the class's internals. If you later decide to validate the data or compute it differently, every caller in the codebase breaks.


Encapsulation

Encapsulation is the idea that an object's data should be hidden behind methods. The class controls how it's read and written; outside code only sees the API.

class Account {
    private decimal balance;

    public void Deposit(decimal amount) {
        if (amount < 0) throw new ArgumentException();
        balance += amount;
    }
}

If balance were public, anyone could write account.balance = -1000; and break the invariant.


The two main modifiers

publicVisible everywhere.
privateVisible only inside the same class.

(There are also protected and internal, which we'll cover when we get to inheritance and assemblies.)


Your task

The Dog class's name field is now private. Add a public string GetName() method that returns it, so the harness in Solution.MagicNumber can read the dog's name.

Dog's name: Rex
STEP 1 OF 2
    Ctrl + Enter to check

    C# · OBJECT-ORIENTED PROGRAMMING

    Access Modifiers in C#, explained

    Why hide anything

    Until now every field in the lessons was public, so any code could read or change it. That is convenient, but it exposes the inside of the class. If you later want to check values before storing them, or store the data differently, every piece of code that touches the field is affected.

    An access modifier is a keyword in front of a member that controls which code may use it. The idea of hiding data and offering controlled access through methods is called encapsulation.

    The main modifiers

    ModifierWho can use the member
    publicAny code.
    privateOnly code inside the same class.
    protectedThe class and classes derived from it.
    internalAny code in the same project (assembly).

    The last two matter once you use inheritance and larger programs. For now, the pair that counts is public and private.

    When you leave the modifier out, C# chooses a default. Members of a class are private by default, so string name; inside a class is private. Writing private explicitly makes the intent obvious. A top-level class without a modifier is internal.

    A private field with a public method

    class Dog {
        private string name;          // hidden from outside
    
        public Dog(string name) {     // anyone can construct a Dog
            this.name = name;
        }
    
        public string GetName() {     // controlled read access
            return name;
        }
    }
    

    Code in another class can call rex.GetName() but cannot write rex.name. That line fails to compile with an error such as 'Dog.name' is inaccessible due to its protection level. Inside Dog, the field is fully available, which is why GetName can return it.

    Private means private to the class, not to the individual object. A method of Dog can read the private field of another Dog:

    public bool SameName(Dog other) {
        return name == other.name;
    }
    

    Protecting rules

    Hiding data lets a class guarantee its own rules. Suppose a bank account must never hold a negative deposit:

    class Account {
        private decimal balance;
    
        public void Deposit(decimal amount) {
            if (amount < 0) throw new ArgumentException("negative");
            balance += amount;
        }
    }
    

    If balance were public, any code could assign account.balance = -1000; and skip the check. With a private field, every change goes through Deposit. Later, you can add logging or limits in one place without touching callers.

    Properties

    Writing a GetName method for each field works, but C# has a built-in feature for this pattern: a property. It reads like a field and can run code behind the scenes:

    class Dog {
        private string name;
    
        public string Name {
            get { return name; }
        }
    }
    

    Code outside writes rex.Name and can read the value, but there is no set, so it can't change it. This lesson uses the explicit GetName() method, which makes the mechanics visible. Properties do the same job with less code.

    Common mistakes

    • Making everything private. If a method that other classes call is private, the call fails. Constructors count too: a private constructor can't be used by new outside the class.
    • Making everything public. It compiles, but it gives up the protection that encapsulation provides.
    • Returning the field under the wrong name. The method is GetName, with capital letters. A call to getName() doesn't match it.
    • Forgetting the return type. A method that returns the name needs string, not void.
    • Thinking private is a security feature. It is a compile-time rule that helps you structure code. It doesn't hide data from the running program.

    The exercise, step by step

    The Dog class now has a private field name and a constructor. The code in MainFunction prints rex.GetName(), so the method has to be added. The expected output is:

    Dog's name: Rex
    
    1. Declare the method below the constructor: public string GetName(). It is public so that Solution can call it, and it returns a string.
    2. Return the field with return name;. This compiles because code inside Dog may use the private field.
    class Dog {
        private string name;
    
        public Dog(string name) {
            this.name = name;
        }
    
        public string GetName() {
            return name;
        }
    }
    
    class Solution {
        public void MainFunction() {
            Dog rex = new Dog("Rex");
            Console.WriteLine("Dog's name: " + rex.GetName());
        }
    }
    

    Key takeaways

    • Access modifiers decide which code may use a member.
    • public is open to everyone; private is limited to the class itself, and it is the default for class members.
    • Keep data private and expose what callers need through public methods or properties.
    • Encapsulation lets a class enforce its own rules.
    • Reading a private field from outside is a compile-time error.
    Keep going with C#About 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free