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
| Modifier | Who can use the member |
|---|---|
public | Any code. |
private | Only code inside the same class. |
protected | The class and classes derived from it. |
internal | Any 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
newoutside 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 togetName()doesn't match it. - Forgetting the return type. A method that returns the name needs
string, notvoid. - 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
- Declare the method below the constructor:
public string GetName(). It ispublicso thatSolutioncan call it, and it returns astring. - Return the field with
return name;. This compiles because code insideDogmay 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.
publicis open to everyone;privateis 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.