Object-Oriented Programming (OOP) in C#

Introduction

Object-Oriented Programming (OOP) is a paradigm centered around objects rather than actions. It encapsulates data and behavior into classes and provides a framework for organizing code in a way that models real-world entities. C#, a modern, object-oriented language developed by Microsoft, incorporates the principles of OOP to provide a robust and flexible programming environment.

This article delves into the key concepts of OOP in C#, including classes and objects, encapsulation, inheritance, polymorphism, and abstraction. We’ll explore these concepts with examples and demonstrate how they can be applied in C# programming.

Key Concepts of OOP

1. Classes and Objects

Classes are blueprints for creating objects. They define the properties (data) and methods (behavior) that the objects created from the class will have. An object is an instance of a class.

Example:

// Define a class named Car
public class Car
{
    // Properties of the class
    public string Make { get; set; }
    public string Model { get; set; }
    public int Year { get; set; }

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

// Using the class
class Program
{
    static void Main()
    {
        // Create an object of the Car class
        Car myCar = new Car();
        myCar.Make = "Toyota";
        myCar.Model = "Camry";
        myCar.Year = 2024;

        // Call the method
        myCar.StartEngine();
    }
}

In this example, Car is a class with properties and a method. myCar is an object of type Car that has its own state and behavior.

2. Encapsulation

Encapsulation is the principle of bundling the data (fields) and the methods (functions) that operate on the data into a single unit, or class. It also involves restricting direct access to some of the object’s components, which can be achieved using access modifiers.

Access Modifiers:

  • public: Accessible from any other code.
  • private: Accessible only within the class itself.
  • protected: Accessible within the class and its subclasses.
  • internal: Accessible within the same assembly.
  • protected internal: Accessible within the same assembly and by derived classes.

Example:

public class Account
{
    // Private field
    private decimal balance;

    // Public property to access private field
    public decimal Balance
    {
        get { return balance; }
        set
        {
            if (value >= 0)
                balance = value;
            else
                Console.WriteLine("Balance cannot be negative.");
        }
    }

    // Public method
    public void Deposit(decimal amount)
    {
        if (amount > 0)
            balance += amount;
    }

    public void Withdraw(decimal amount)
    {
        if (amount > 0 && amount <= balance)
            balance -= amount;
    }
}

In this example, the balance field is private, and it is accessed and modified through the public Balance property. This ensures that balance can only be modified in controlled ways.

3. Inheritance

Inheritance is a mechanism where a new class (derived class) inherits properties and methods from an existing class (base class). It promotes code reusability and establishes a hierarchical relationship between classes.

Example:

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

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

// Using the classes
class Program
{
    static void Main()
    {
        Dog myDog = new Dog();
        myDog.Eat();  // Inherited method
        myDog.Bark(); // Method of the Dog class
    }
}

Here, Dog inherits the Eat method from the Animal class and adds its own method Bark.

4. Polymorphism

Polymorphism allows objects to be treated as instances of their base class rather than their actual class. It enables methods to have the same name but behave differently based on the object’s actual class. There are two types of polymorphism: compile-time (method overloading) and runtime (method overriding).

Method Overloading (Compile-Time Polymorphism):

Method overloading allows multiple methods with the same name but different parameters.

Example:

public class MathOperations
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public double Add(double a, double b)
    {
        return a + b;
    }
}

Method Overriding (Runtime Polymorphism):

Method overriding allows a derived class to provide a specific implementation of a method that is already defined in its base class.

Example:

// Base class
public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("Some generic animal sound");
    }
}

// Derived class
public class Cat : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Meow");
    }
}

// Using the classes
class Program
{
    static void Main()
    {
        Animal myAnimal = new Cat();
        myAnimal.MakeSound();  // Outputs: Meow
    }
}

In this example, MakeSound is overridden in the Cat class, and the overridden method is called through a base class reference.

5. Abstraction

Abstraction involves hiding the complex implementation details and showing only the necessary features of an object. It is achieved using abstract classes and interfaces.

Abstract Classes:

An abstract class cannot be instantiated directly and can contain abstract methods (without implementation) that must be implemented by derived classes.

Example:

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

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

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

Interfaces:

An interface defines a contract for what methods a class must implement, but it does not provide the method implementations.

Example:

public interface IDrawable
{
    void Draw();
}

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

public class Rectangle : IDrawable
{
    public void Draw()
    {
        Console.WriteLine("Drawing a rectangle");
    }
}

Conclusion

Object-Oriented Programming in C# provides a powerful framework for designing and managing code by modeling real-world entities through classes and objects. Understanding and applying the core principles of encapsulation, inheritance, polymorphism, and abstraction helps in creating well-structured, maintainable, and reusable code. By leveraging these OOP concepts effectively, developers can build robust applications that are easier to understand, extend, and maintain.

Leave a Reply