C# - Classes
C# - Classes and Objects
Section titled “C# - Classes and Objects”Classes are the cornerstone of object-oriented programming (OOP) in C#. A class is a blueprint for creating objects. It defines a set of properties (data) and methods (behaviors) that the objects of that class will have. An object is an instance of a class, a concrete entity created from the blueprint.
Think of a Car class as the blueprint. It defines that all cars have properties like Color, Make, and Model, and methods like StartEngine() and Accelerate(). An actual car, like a “red Tesla Model S”, is an object (an instance) of the Car class.
Defining a Class
Section titled “Defining a Class”A class is defined with the class keyword. Modern C# uses properties to expose data, which provide a clean syntax for getting and setting values while enabling logic behind the scenes.
public class BankAccount{ // Properties: Publicly accessible data members public string AccountNumber { get; set; } public string Owner { get; set; }
// A property with a private setter to control modifications public decimal Balance { get; private set; }
// Constructor: A special method for creating and initializing objects public BankAccount(string owner, decimal initialBalance) { Owner = owner; Balance = initialBalance; AccountNumber = Guid.NewGuid().ToString(); // Generate a unique account number }
// Methods: Actions the object can perform public void Deposit(decimal amount) { if (amount <= 0) { throw new ArgumentOutOfRangeException(nameof(amount), "Deposit amount must be positive."); } Balance += amount; }
public void Withdraw(decimal amount) { if (amount <= 0) { throw new ArgumentOutOfRangeException(nameof(amount), "Withdrawal amount must be positive."); } if (Balance - amount < 0) { throw new InvalidOperationException("Insufficient funds."); } Balance -= amount; }}Creating and Using Objects
Section titled “Creating and Using Objects”You create an object (instantiate a class) using the new keyword. Once you have an object, you can access its public members using the dot (.) operator.
using System;
// Create an instance of the BankAccount classvar myAccount = new BankAccount("Alice Smith", 1000.00m);
Console.WriteLine($"Account created for {myAccount.Owner}.");Console.WriteLine($"Account Number: {myAccount.AccountNumber}");Console.WriteLine($"Initial Balance: {myAccount.Balance:C}");
// Use the object's methodsmyAccount.Deposit(250.50m);Console.WriteLine($"New balance after deposit: {myAccount.Balance:C}");
try{ myAccount.Withdraw(500.00m); Console.WriteLine($"New balance after withdrawal: {myAccount.Balance:C}"); myAccount.Withdraw(2000.00m); // This will throw an exception}catch (InvalidOperationException ex){ Console.WriteLine($"Error: {ex.Message}");}Output
Section titled “Output”Account created for Alice Smith.Account Number: [A unique GUID will be shown here]Initial Balance: $1,000.00New balance after deposit: $1,250.50New balance after withdrawal: $750.50Error: Insufficient funds.Encapsulation and Access Modifiers
Section titled “Encapsulation and Access Modifiers”Encapsulation, or data hiding, is a core OOP principle. It means bundling the data (properties) and methods that operate on that data within a single unit (the class) and controlling access to that data from the outside. This prevents accidental corruption and keeps the internal state of the object valid.
Access modifiers control the visibility of a class and its members:
public: Accessible from anywhere.private: Accessible only within the same class. This is the default for members.protected: Accessible within the class and by derived (child) classes.internal: Accessible only within the same project (assembly). This is the default for classes.protected internal: Accessible within the same project OR from derived classes in other projects.private protected: Accessible by derived classes, but only within the same project.
In our BankAccount example, Balance has a private set. This means anyone can read the balance, but only code inside the BankAccount class (like the Deposit and Withdraw methods) can change it. This is a perfect example of encapsulation.
Constructors and Object Initialization
Section titled “Constructors and Object Initialization”A constructor is a special method called when an object is created. Its purpose is to initialize the object’s state. If you don’t define a constructor, a default parameterless one is provided for you.
You can also use object initializers for a more readable way to set public properties after the constructor runs.
public class Customer{ public int Id { get; set; } public string Name { get; set; } = "Anonymous"; // Default value public bool IsPremium { get; set; }
// Parameterless constructor public Customer() {}}
// Using the parameterless constructor and an object initializervar customer = new Customer{ Id = 101, Name = "Bob Johnson", IsPremium = true};Static Members
Section titled “Static Members”A static member (property or method) belongs to the class itself, not to an instance of the class. You access it using the class name, not an object variable. Static members are shared across all instances of the class.
public class ConfigurationManager{ // Static property - only one copy exists for the entire application public static string ApiUrl { get; set; } = "https://api.example.com";
// Static method public static void LoadConfiguration() { Console.WriteLine($"Loading configuration from {ApiUrl}..."); }}
// Accessing static members using the class nameConfigurationManager.LoadConfiguration();ConfigurationManager.ApiUrl = "https://api-test.example.com";Console.WriteLine($"API URL set to: {ConfigurationManager.ApiUrl}");Resource Management: IDisposable
Section titled “Resource Management: IDisposable”In older C#, destructors (~ClassName()) were sometimes mentioned. However, the modern and correct way to handle resource cleanup (like closing files, network connections, or database handles) is by implementing the IDisposable interface and using the using statement.
public class FileReader : IDisposable{ private StreamReader _reader;
public FileReader(string filePath) { _reader = new StreamReader(filePath); }
public string ReadLine() => _reader.ReadLine();
// The Dispose method cleans up the resource public void Dispose() { _reader?.Dispose(); Console.WriteLine("File reader disposed."); }}
// The 'using' statement ensures Dispose() is called automatically// even if errors occur.using (var reader = new FileReader("mydata.txt")){ // use the reader...}// At this point, reader.Dispose() has been called.