OOP in C#
Object-Oriented Programming (OOP) is a programming paradigm that is widely used in C# and .NET, based on the concept of “Objects”, which can contain data and methods to manipulate that data. The key OOP concepts used in C# and .NET include:
Class and Object:
- Class: A class is a blueprint for creating objects. It defines the properties (data members) and behaviors (methods) that objects of the class will have. Ex:
BankAccount
- Object: An object is an instance of a class. It is a runtime entity with a state and behavior as defined by its class. Ex:
myAccount
public class BankAccount
{
public string AccountHolder { get; set; }
public decimal Balance { get; private set; }
public void Deposit(decimal amount)
{
// Validation logic can be added
Balance += amount;
}
public void Withdraw(decimal amount)
{
// Validation logic can be added
Balance -= amount;
}
}
// Creating an object of the BankAccount class
BankAccount myAccount = new BankAccount();
myAccount.AccountHolder = "John Doe";
myAccount.Deposit(1000);
myAccount.Withdraw(200);
Encapsulation:
- Encapsulation is the bundling of data (attributes) and the methods that operate on the data into a single unit (class). It restricts direct access to some of an object’s components, emphasizing the idea of hiding the internal state of the object.
- Encapsulation restricts direct access and prevents the accidental modification of data.
public class BankAccount
{
private decimal balance;
public BankAccount (decimal initialBalance)
{
balance = initialBalance;
}
public void Deposit(decimal amount)
{
balance += amount;
}
public void Withdraw(decimal amount)
{
if(balance >= amount){
balance -= amount;
}
else {
Console.WriteLine("Insufficiant Balance");
}
}
public decimal GetBalance()
{
return balance;
}
}
The ‘balance’ field is declared as ‘private’ and this can be only accessed within the ‘BankAccount’ class.
‘Deposit’ and ‘Withdraw’ methods are the only way to change balance and they have controlled access to modify the ‘balance’. So, ‘balance’ cannot be directly modified from outside the class.
‘GetBalance()’ method is provided to retrieve the balance. This provides read only access to the balance field.
Inheritance:
- Inheritance allows a class (subclass/derived class) to inherit the properties and behaviors of another class (base class/parent class). It promotes code reusability.
- Introducing different types of bank accounts that inherit from a common
Account
class.
public class Account
{
public string AccountHolder { get; set; }
protected decimal balance;
public void Deposit(decimal amount)
{
// Validation logic can be added
balance += amount;
}
public void Withdraw(decimal amount)
{
// Validation logic can be added
balance -= amount;
}
public decimal GetBalance()
{
return balance;
}
}
public class SavingsAccount : Account
{
// Additional properties or methods specific to SavingsAccount
}
public class CheckingAccount : Account
{
// Additional properties or methods specific to CheckingAccount
}
Polymorphism:
- Polymorphism allows objects of different classes to be treated as objects of a common superclass. It can be achieved through method overloading and method overriding.
- Using polymorphism to handle various types of accounts uniformly.
Overriding
This occurs when subclass provides a specific implementation of a method, that is already defined in the superclass. This allows subclass to provide a its own behavior while still maintaining a common interface with its superclass.
public class Product
{
// Other code
public virtual decimal GetPrice();
{
return price;
}
}
public class DiscountedProduct : Product
{
// Other code
public override decimal GetPrice();
{
return price - (Price * Discount / 100);
}
}
Overloading
This occurs when the class has methods with same name, but with different parameters.
public class Product
{
// Other code
public decimal CalculateTotalPrice (int quantity, decimal price);
{
return price * quantity;
}
public decimal CalculateTotalPrice (int quantity, decimal price, decimal discount);
{
return (price * quantity) - discount;
}
}
- Abstract and virtual keywords are used to achieve polymorphism.
- Virtual used with methods, properties or indexes. Virtual methods have a default implementation which can be overridden in derived classes and classes containing virtual members can be instantiated.
- Abstraction used with classes, methods or properties.
- The relationship between abstraction and polymorphism lies in the use of abstract classes and interfaces to define common interfaces and behaviors, which are implemented by concrete classes. this enables the polymorphic behavior, where different subclasses can provide their own implementations of methods defined in abstract classes or interfaces.
Abstraction:
- Abstraction is the process of hiding the complex implementation details and showing only the essential features of an object. It is achieved through abstract classes and interfaces.
- Using abstraction to define a common interface for different types of accounts.
- This can be achieved through Abstract Classes or Interfaces
This how Abstraction implemented through Interfaces.
public interface IService
{
void TotalCost(decimal servicePrice, int hours); // method signature
}
public class InShopService : IService
{
public void TotalCost(decimal servicePrice, int hours)
{
return servicePrice * hours;
}
}
public class HomeVisitServices : IService
{
public void TotalCost(decimal servicePrice, int hours)
{
return (servicePrice * hours) + visitFee;
}
}
This how Abstraction implemented through Abstract Classes.
public abstract class Service
{
public abstract decimal TotalCost(decimal servicePrice, int hours); // abstract method signature
public decimal GetUnitPrice() // normal method implementation
{
return unitPrice;
}
public decimal CalculateDiscount() // virtual method implementation
{
decimal calculatedDiscount = (price * 10/100);
}
}
public class InShopService : Service
{
public override double TotalCost(decimal servicePrice, int hours)
{
return servicePrice * hours;
}
}
public class HomeVisitServices : Service
{
public override decimal TotalCost(decimal servicePrice, int hours)
{
return (servicePrice * hours) + visitFee;
}
}
Abstract Classes VS Interfaces
Abstract Classes
- Abstract classes can have normal methods, abstract methods and virtual methods. Abstract methods should come under an abstract class and contains only method signature. They should be implemented in a derived class. Virtual methods in abstract class has a default implementation which can be overridden in derived class.
- Cannot be instantiated directly.
- Focuses on hiding implementation detail and showing only essential features of an object.
Define a common interface while proving flexibility in how concreate classes implement it. - Provide common base implementation along with some abstract methods that must be implemented by subclass.
- Can define some default implementation for some methods, which can be overridden by subclasses.
- Only single inheritance is allowed.
Interfaces
- It defines a contract that specifies a set of methods and properties that must be implemented.
They enable multiple classes to share common set of behavior, without specifying the implementation. - Cannot be instantiated directly.
- Explicitly declared as ‘interface’ and only contain method signatures without any implementation.
- Used when needed to define a contract that multiple unrelated classes can adhere to.
- Cannot have any implemented methods inside an interface.
- Multiple inheritance allowed.
OOP principals promotes developers to write modular, maintainable and scalable code with reusability, extensibility and flexibility. This makes fundamental paradigm in modern software engineering.