;

C# OOP


Object-Oriented Programming (OOP) is a programming paradigm that provides a way to structure your code using objects, which can contain both data (in the form of fields or properties) and methods (functions or behaviors). In C#, OOP is the backbone of developing clean, reusable, and scalable applications. It is used to model real-world systems by organizing code around four key principles: Encapsulation, Inheritance, Polymorphism, and Abstraction.

This tutorial will walk you through the fundamentals of C# OOP, discuss its key concepts, and provide practical examples to help you understand how these principles can be used in real-world scenarios.

What is Object-Oriented Programming?

Object-Oriented Programming (OOP) is a paradigm based on the concept of "objects" which represent real-world entities. These objects can hold data (in the form of fields or properties) and provide behavior through methods. C# is a fully OOP language, which allows you to break down complex systems into simpler, reusable pieces.

An object is an instance of a class, where the class acts as a blueprint defining the properties and behaviors that objects will have.

class Car
{
    // Fields or properties (data)
    public string Model;
    public int Year;

    // Constructor
    public Car(string model, int year)
    {
        Model = model;
        Year = year;
    }

    // Method (behavior)
    public void StartEngine()
    {
        Console.WriteLine("Engine started.");
    }
}

Car myCar = new Car("Tesla", 2023); // Creating an object
myCar.StartEngine(); // Calling method

Key Principles of OOP

C# OOP revolves around four core principles: Encapsulation, Inheritance, Polymorphism, and Abstraction. These principles guide how classes interact and how they are structured to ensure flexibility, reusability, and simplicity.

Encapsulation

Encapsulation is the concept of bundling the data (fields) and methods (functions) that operate on the data into a single unit called a class. It also involves restricting direct access to some of the object's components and only exposing necessary parts using access modifiers like public, private, protected, and internal.

Encapsulation allows data hiding, ensuring that the internal workings of an object are hidden from the outside world.

Example:

public class BankAccount
{
    // Private field (hidden from outside access)
    private decimal balance;

    // Public method to access hidden data safely
    public void Deposit(decimal amount)
    {
        if (amount > 0)
        {
            balance += amount;
            Console.WriteLine($"Deposited: {amount}, Current balance: {balance}");
        }
    }

    public decimal GetBalance()
    {
        return balance;
    }
}

BankAccount account = new BankAccount();
account.Deposit(500);
Console.WriteLine($"Balance: {account.GetBalance()}");
// Output: Deposited: 500, Current balance: 500
//         Balance: 500

Use Case:

  • Banking systems, where sensitive information like balances needs to be protected from outside tampering but still needs to be manipulated in a controlled manner.

Inheritance

Inheritance allows a new class (derived class or child class) to inherit the properties and methods of an existing class (base class or parent class). This promotes code reusability and creates a relationship between classes.

Example:

// Base class
public class Animal
{
    public void Eat()
    {
        Console.WriteLine("Animal is eating.");
    }
}

// Derived class
public class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine("Dog is barking.");
    }
}

Dog myDog = new Dog();
myDog.Eat();  // Inherited method
myDog.Bark(); // Method in Dog class

Use Case:

  • Game development, where a base Character class can provide common behaviors like moving and attacking, while derived classes like Player and Enemy can add their unique behaviors like special abilities.

Polymorphism

Polymorphism allows you to invoke derived class methods through a base class reference during runtime, facilitating flexible and interchangeable code. It enables methods to perform differently based on the object calling them, even though they share the same name.

Example:

public class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("Animal sound.");
    }
}

public class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Bark!");
    }
}

public class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Meow!");
    }
}

Animal myDog = new Dog();
Animal myCat = new Cat();

myDog.Speak(); // Output: Bark!
myCat.Speak(); // Output: Meow!

Use Case:

  • User interfaces, where different types of controls like buttons, text boxes, and labels can have different behaviors while sharing a common base class for basic properties.

Abstraction

Abstraction is the process of hiding the complex implementation details and exposing only the essential features of an object. It reduces complexity and increases the ease of use for end-users by providing a simple interface.

Example:

public abstract class Shape
{
    public abstract void Draw();
}

public class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle.");
    }
}

public class Square : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a square.");
    }
}

Shape myShape = new Circle();
myShape.Draw();  // Output: Drawing a circle.

Use Case:

  • Graphical applications, where base classes like Shape provide abstract behaviors like Draw(), but each specific shape (e.g., Circle, Square) implements how it should actually be drawn.

Real-World Example: E-commerce System

Let’s walk through a real-world example using an e-commerce system to demonstrate how OOP principles come together in a practical use case.

Scenario

In an e-commerce application, you need to manage different types of users, such as Customers, Sellers, and Admins. Each user shares common properties like Name and Email, but they also have specific behaviors. For example, a customer can place orders, while a seller can list products.

Implementation

Step 1: Base Class (User)
public class User
{
    public string Name { get; set; }
    public string Email { get; set; }

    public User(string name, string email)
    {
        Name = name;
        Email = email;
    }

    public void Login()
    {
        Console.WriteLine($"{Name} logged in.");
    }
}
Step 2: Derived Classes (Customer, Seller, Admin)
public class Customer : User
{
    public Customer(string name, string email) : base(name, email) { }

    public void PlaceOrder()
    {
        Console.WriteLine($"{Name} placed an order.");
    }
}

public class Seller : User
{
    public Seller(string name, string email) : base(name, email) { }

    public void ListProduct()
    {
        Console.WriteLine($"{Name} listed a product.");
    }
}

public class Admin : User
{
    public Admin(string name, string email) : base(name, email) { }

    public void ManageUsers()
    {
        Console.WriteLine($"{Name} managed users.");
    }
}
Step 3: Usage
Customer customer = new Customer("John Doe", "john@example.com");
Seller seller = new Seller("Jane Doe", "jane@example.com");
Admin admin = new Admin("Admin", "admin@example.com");

customer.Login();
customer.PlaceOrder();

seller.Login();
seller.ListProduct();

admin.Login();
admin.ManageUsers();

Key Takeaways:

  1. Encapsulation ensures that each class handles its own data and functionality. For example, users can log in, and customers can place orders without revealing the inner workings of these processes. 
  2. Encapsulation hides the internal state of objects and provides controlled access through methods.
  3. Inheritance allows shared properties and methods to be defined in the User class and inherited by the specialized Customer, Seller, and Admin classes.
  4. Inheritance allows you to create new classes based on existing ones, fostering code reuse.
  5. Polymorphism could be applied if we needed a method like ManageAccount() in the base class and different implementations in the derived classes.
  6. Polymorphism enables objects of different types to be treated as objects of a common base type, making code more flexible and extensible.
  7. Abstraction simplifies user management by providing a clear and simple interface for user actions like logging in and managing orders.
  8. Abstraction simplifies complex systems by hiding unnecessary details and showing only essential features.

Summary

Object-Oriented Programming (OOP) is a foundational concept in C# and is essential for writing clean, modular, and scalable code. By understanding and applying the principles of Encapsulation, Inheritance, Polymorphism, and Abstraction, you can build systems that reflect real-world problems while promoting reusability and maintainability.

By mastering these principles, you will be able to design robust, maintainable, and scalable applications in C#.