Hello! In this lesson, we're revisiting Encapsulation, Private Attributes, and Private Methods in Object-Oriented Programming (OOP). Imagine encapsulation as an invisible fence safeguarding a garden from outside interference, keeping data and methods safe within. Within this garden, certain plants (Private Attributes and Methods) are only for the gardener's eyes. These are crucial for making your classes more robust and secure!
Encapsulation is a fundamental concept in Object-Oriented Programming (OOP) that involves bundling data (attributes) and methods (functions) that operate on the data into a single unit, called a class. This concept also restricts direct access to some of an object's components, thereby preventing accidental interference and misuse of the data. If you were to code a multiplayer game, for instance, you could create a Player
class, encapsulating data (health
, armor
, stamina
) and methods (ReceiveDamage
, ShieldHit
, RestoreHealth
).
C#1public class Player { 2 private int health; 3 private int armor; 4 private int stamina; 5 6 public Player(int health, int armor, int stamina) { 7 this.health = health; 8 this.armor = armor; 9 this.stamina = stamina; 10 } 11 12 public void ReceiveDamage(int damage) { 13 health -= damage; // Reduce health 14 } 15 16 public void ShieldHit(int armorDamage) { 17 armor -= armorDamage; // Decrease armor 18 } 19 20 public void RestoreHealth(int healthIncrease) { 21 health += healthIncrease; // Restore health 22 } 23} 24 25class Program { 26 static void Main() { 27 Player player = new Player(100, 50, 77); 28 } 29}
Now, player
is an instance of the Player
class on which you can call methods.
In C#, the private
keyword designates an attribute or method as limited to the class itself, meaning it cannot be accessed directly from outside the class. Note that the constructor itself cannot be private.
C#1public class PrivateExample { 2 private string privateAttribute; // Declare a private field 3 4 public string PublicAttribute { get; set; } 5 6 public PrivateExample() { 7 PublicAttribute = "Public"; 8 privateAttribute = "Private"; // Initialize private attribute 9 } 10 11 public string GetPrivateAttribute() { 12 return privateAttribute; 13 } 14} 15 16class Program { 17 static void Main() { 18 PrivateExample example = new PrivateExample(); 19 Console.WriteLine(example.PublicAttribute); // Works: logs "Public" 20 Console.WriteLine(example.GetPrivateAttribute()); // Works: logs "Private" 21 // Console.WriteLine(example.privateAttribute); // Error: can't access private attribute from outside 22 } 23}
Private attributes and methods are inaccessible directly from an instance. This arrangement helps maintain integrity.
Private Attributes, which can only be altered via class methods, limit outside interference. For instance, a BankAccount
class might feature a balance
private attribute that one could change only through deposits or withdrawals. If you try to access bankAccount.balance
directly in the main method, it will throw an error because balance
is private.
C#1public class BankAccount { 2 private decimal balance; // Declare a private field 3 4 public int AccountNumber { get; } 5 6 public BankAccount(int accountNumber, decimal balance) { 7 AccountNumber = accountNumber; 8 this.balance = balance; // Initialize the private attribute 9 } 10 11 public void Deposit(decimal amount) { 12 balance += amount; // Deposit money 13 } 14 15 public decimal GetBalance() { 16 return balance; // A public method to access balance 17 } 18} 19 20class Program { 21 static void Main() { 22 BankAccount bankAccount = new BankAccount(1234, 100); 23 Console.WriteLine(bankAccount.GetBalance()); // Works: logs 100 24 // Console.WriteLine(bankAccount.balance); // Error: can't access private attribute from outside 25 } 26}
Here, balance
is private, thus ensuring the integrity of the account balance. It can't be accessed directly from outside the class.
Like private attributes, private methods are accessible only within their class. They are useful when you want to hide complex implementation details or helper functions from outside access. Here's an example:
C#1public class BankAccount { 2 private decimal balance; // Declare a private field 3 4 public int AccountNumber { get; } 5 6 public BankAccount(int accountNumber, decimal balance) { 7 AccountNumber = accountNumber; 8 this.balance = balance; 9 } 10 11 // Private method 12 private void AddInterest(decimal interestRate) { 13 balance += balance * interestRate; // Calculation of interest 14 } 15 16 // Public method calling the private method 17 public void AddYearlyInterest() { 18 AddInterest(0.02m); // Adds 2% interest 19 } 20 21 public decimal GetBalance() { 22 return balance; 23 } 24} 25 26class Program { 27 static void Main() { 28 BankAccount bankAccount = new BankAccount(1234, 100); 29 bankAccount.AddYearlyInterest(); // Works, calling a public method 30 Console.WriteLine(bankAccount.GetBalance()); // Logs the updated balance 31 // bankAccount.AddInterest(0.1m); // Error: can't call a private method from outside 32 } 33}
Here, AddYearlyInterest()
is a public method that calls the private method AddInterest()
.
In C#, properties provide a way to access and mutate private attributes indirectly while maintaining control over how values are retrieved or changed. This remains in line with the encapsulation principle by providing a controlled interface to interact with private data.
Properties allow access to the value of a private attribute in a safe, controlled manner. Here's how you can define a property for a private attribute:
C#1public class BankAccount { 2 private decimal balance; // Declare a private field 3 4 public int AccountNumber { get; } 5 6 public BankAccount(int accountNumber, decimal balance) { 7 AccountNumber = accountNumber; 8 this.balance = balance; // Initialize the private attribute 9 } 10 11 // Property for balance 12 public decimal Balance { 13 get { return balance; } 14 } 15 16 public void Deposit(decimal amount) { 17 balance += amount; // Deposit money 18 } 19} 20 21class Program { 22 static void Main() { 23 BankAccount bankAccount = new BankAccount(1234, 100); 24 Console.WriteLine(bankAccount.Balance); // Works: logs 100 25 } 26}
In this example, the Balance
property provides a safe way to access the private balance
attribute.
Properties allow modification of the value of a private attribute while providing a controlled interface. Here’s how you can define a property with a setter for a private attribute:
C#1public class BankAccount { 2 private decimal balance; // Declare a private field 3 4 public int AccountNumber { get; } 5 6 public BankAccount(int accountNumber, decimal balance) { 7 AccountNumber = accountNumber; 8 this.balance = balance; // Initialize the private attribute 9 } 10 11 // Property for balance 12 public decimal Balance { 13 get { return balance; } 14 set { 15 if (value >= 0) { 16 balance = value; 17 } else { 18 Console.WriteLine("Balance cannot be negative."); 19 } 20 } 21 } 22 23 public void Deposit(decimal amount) { 24 balance += amount; // Deposit money 25 } 26} 27 28class Program { 29 static void Main() { 30 BankAccount bankAccount = new BankAccount(1234, 100); 31 bankAccount.Balance = 200; // Works: sets balance to 200 32 Console.WriteLine(bankAccount.Balance); // Works: logs 200 33 bankAccount.Balance = -50; // Logs: "Balance cannot be negative." 34 } 35}
In this example, the Balance
property ensures that the balance
is only set to non-negative values, adding a layer of validation.
By using properties, you can add logic for validating or transforming data, making your class more flexible and secure while adhering to encapsulation principles.
Great job refreshing your understanding of encapsulation, private attributes, and private methods concepts in C#! Correctly understanding and applying these foundational principles of OOP make your code concise, robust, and secure.
Coming up next is hands-on practice. Keep up the good work — exciting exercises are just around the corner!