Greetings! Today, we're revisiting C# classes, the core building block of Object-Oriented Programming (OOP) in C#. Classes play a pivotal role in structuring code to model real-world entities and behaviors. Through hands-on examples, we'll revisit the fundamental concepts of C# classes, including their structure, properties, and methods. This session aims to enhance your understanding of how classes facilitate better code organization and reusability.
Let's begin with a refresher on C# classes. Essential to OOP, C# classes bundle relevant data and functions into compact units called objects. Consider a video game character, which is a typical example of a class instance, with specific properties (such as Health
and Strength
) and methods (such as Attack
).
C#1public class GameCharacter 2{ 3 // Fields 4 private string name; 5 private int health; 6 private int strength; 7 8 // Constructor method 9 public GameCharacter(string name, int health, int strength) 10 { 11 this.name = name; // Property 12 this.health = health; // Property 13 this.strength = strength; // Property 14 } 15 16 // Method 17 public void Attack(GameCharacter otherCharacter) 18 { 19 otherCharacter.health -= this.strength; 20 } 21 22 // Properties 23 public string Name 24 { 25 get { return name; } 26 } 27 28 public int Health 29 { 30 get { return health; } 31 } 32 33 public int Strength 34 { 35 get { return strength; } 36 } 37}
In the code above, the GameCharacter
class has properties Name
, Health
, and Strength
. Each of these properties includes a getter, which allows the retrieval of the corresponding private field values—name
, health
, and strength
. Getters provide a way to access these private fields from outside the class, maintaining encapsulation while allowing read-only access to these properties.
C# classes facilitate the grouping of associated code elements, simplifying their management. Now, let's go through it step-by-step to better understand how the above example works.
A C# class serves as a blueprint consisting of properties and methods. While properties represent data relevant to a class instance, methods are actions or functions that manipulate this data. Each class includes a constructor
function, which is used to define class properties. A constructor is a special method that is called when an object of the class is created.
An essential keyword within these methods is this
, which represents the class instance. In the constructor, this.name
refers to the class property name
, while name
refers to the parameter passed to the constructor. In object-oriented programming, this
is needed to access the class's properties and methods. When a new class instance is created, C# automatically passes it to the this
parameter to access individual instance properties and methods using the this
keyword. This mechanism allows each object to keep track of its own state and behaviors.
When creating an instance of the class, parameters are passed to the constructor, and a new instance of the class is created, as demonstrated in GameCharacter character = new GameCharacter("Hero", 100, 20);
.
C#1public class GameCharacter 2{ 3 // Fields 4 private string name; 5 private int health; 6 private int strength; 7 8 // Constructor: Defines class properties 9 public GameCharacter(string name, int health, int strength) 10 { 11 this.name = name; // Property 12 this.health = health; // Property 13 this.strength = strength; // Property 14 } 15 16 // Properties 17 public string Name 18 { 19 get { return name; } 20 } 21 22 public int Health 23 { 24 get { return health; } 25 } 26 27 public int Strength 28 { 29 get { return strength; } 30 } 31} 32 33public class Program 34{ 35 public static void Main(string[] args) 36 { 37 GameCharacter character = new GameCharacter("Hero", 100, 20); // Object or instance of the class 38 } 39}
Properties in C# classes hold data associated with each class instance. For example, in our GameCharacter
class, Name
, Health
, and Strength
are properties.
In the code block, we create a GameCharacter
object and store it in the character
variable with the name 'Hero', health set to 100, and strength set to 20. We can then access its name by using character.Name
, which will return 'Hero'. Similarly, character.Health
returns 100, and character.Strength
returns 20.
C#1public class GameCharacter 2{ 3 // Fields 4 private string name; 5 private int health; 6 private int strength; 7 8 // Constructor: Defines class properties 9 public GameCharacter(string name, int health, int strength) 10 { 11 this.name = name; // Property 12 this.health = health; // Property 13 this.strength = strength; // Property 14 } 15 16 // Properties 17 public string Name 18 { 19 get { return name; } 20 } 21 22 public int Health 23 { 24 get { return health; } 25 } 26 27 public int Strength 28 { 29 get { return strength; } 30 } 31} 32 33public class Program 34{ 35 public static void Main(string[] args) 36 { 37 GameCharacter character = new GameCharacter("Hero", 100, 20); // Object or instance of the class 38 Console.WriteLine(character.Name); // Prints: Hero 39 Console.WriteLine(character.Health); // Prints: 100 40 Console.WriteLine(character.Strength); // Prints: 20 41 } 42}
Properties differentiate one class instance from another and store the state of the instance.
A class also contains methods — actions or functions that manipulate the data in the class. For example, the Attack
method in our GameCharacter
class simulates an attack by one game character on another.
C#1public class GameCharacter 2{ 3 // Fields 4 private string name; 5 private int health; 6 private int strength; 7 8 // Constructor: Defines class properties 9 public GameCharacter(string name, int health, int strength) 10 { 11 this.name = name; // Property 12 this.health = health; // Property 13 this.strength = strength; // Property 14 } 15 16 // Method 17 public void Attack(GameCharacter otherCharacter) 18 { 19 otherCharacter.health -= this.strength; // Modifies 'otherCharacter's health property 20 } 21 22 // Properties 23 public string Name 24 { 25 get { return name; } 26 } 27 28 public int Health 29 { 30 get { return health; } 31 } 32 33 public int Strength 34 { 35 get { return strength; } 36 } 37} 38 39public class Program 40{ 41 public static void Main(string[] args) 42 { 43 GameCharacter character1 = new GameCharacter("Hero", 100, 20); // First instance of GameCharacter 44 GameCharacter character2 = new GameCharacter("Villain", 80, 15); // Second instance 45 46 Console.WriteLine(character2.Health); // Prints: 80 47 character1.Attack(character2); // character1 attacks character2 48 Console.WriteLine(character2.Health); // Prints: 60 49 } 50}
This code demonstrates object interaction using the Attack
method. Initially, character2
has a health of 80. character1
invokes the Attack
method on character2
, reducing the health of character2
by character1
's strength (20). After the attack, character2
's health decreases to 60.
To deepen our understanding of C# classes, let's explore another example where we build a basic BankAccount
class. This class will demonstrate how we can model real-world entities using object-oriented programming by defining properties like the account holder's name and balance, and methods for depositing and withdrawing money.
C#1// Define the BankAccount class 2public class BankAccount 3{ 4 // Fields 5 private string holderName; 6 private decimal balance; 7 8 // Constructor with a default balance of 0 9 public BankAccount(string holderName, decimal balance = 0) 10 { 11 this.holderName = holderName; 12 this.balance = balance; 13 } 14 15 // Method to deposit money 16 public void Deposit(decimal amount) 17 { 18 if (amount > 0) 19 { 20 this.balance += amount; 21 Console.WriteLine($"{amount} deposited. New balance: {this.balance}"); 22 } 23 else 24 { 25 Console.WriteLine("Deposit amount must be positive."); 26 } 27 } 28 29 // Method to withdraw money 30 public void Withdraw(decimal amount) 31 { 32 if (0 < amount && amount <= this.balance) 33 { 34 this.balance -= amount; 35 Console.WriteLine($"{amount} withdrawn. Remaining balance: {this.balance}"); 36 } 37 else 38 { 39 Console.WriteLine("Insufficient balance for the withdrawal or amount is not positive."); 40 } 41 } 42 43 // Properties 44 public string HolderName 45 { 46 get { return holderName; } 47 } 48 49 public decimal Balance 50 { 51 get { return balance; } 52 } 53} 54 55public class Program 56{ 57 public static void Main(string[] args) 58 { 59 // Create an instance of BankAccount 60 BankAccount account = new BankAccount("Alex", 1000); // An account with an initial balance of 1000 61 62 // Perform some transactions 63 account.Deposit(500); // Deposit money 64 // Output: 500 deposited. New balance: 1500 65 66 account.Withdraw(200); // Withdraw money 67 // Output: 200 withdrawn. Remaining balance: 1300 68 69 Console.WriteLine($"Final balance in {account.HolderName}'s account: {account.Balance}"); 70 // Output: Final balance in Alex's account: 1300 71 } 72}
In the BankAccount
class, the properties HolderName
and Balance
include getters that enable access to the private fields holderName
and balance
. These getters allow external code to retrieve the account holder's name and account balance while maintaining data encapsulation, as the fields are not directly accessible from outside the class.
This example further illustrates how classes effectively encapsulate data (properties) and functionalities (methods), enabling us to mimic real-life scenarios. Here, the BankAccount
class allows the creation of objects representing bank accounts, emphasizing the powerful organizational benefits of using classes in C#.
Great work revisiting C# classes, their properties, and methods. C# classes help organize your code, improving its readability and manageability. Now, test your understanding with exercise problems to solidify your newly refreshed knowledge. Happy coding!