Object-Oriented Programming (OOP) remains the foundation of backend development in .NET—even with the growing popularity of functional paradigms. With modern C# (versions 10–12), we can apply classic OOP principles with more clarity, safety, and productivity.
This article explores how to use encapsulation, inheritance, polymorphism, and abstraction using modern C# features like:
record
andrecord struct
required
andinit
sealed
,abstract
, andvirtual
with
expressionsfile-scoped namespace
primary constructors
(C# 12)
🧱 1. Encapsulation with init
and required
public class Customer
{
public required string Name { get; init; }
public required string Email { get; init; }
public DateTime CreatedAt { get; } = DateTime.UtcNow;
}
init
ensures immutability after object construction.required
forces initialization at compile time, avoiding null issues.
🧠 2. Abstraction and Polymorphism with Interfaces
public interface INotificationService
{
void Send(string message);
}
public class EmailService : INotificationService
{
public void Send(string message)
=> Console.WriteLine($"Email sent: {message}");
}
Code is decoupled and testable via Dependency Injection.
OOP + SOLID principles like Interface Segregation and Dependency Inversion.
🧬 3. Inheritance with abstract
, sealed
, and override
public abstract class Employee
{
public abstract decimal CalculateSalary();
}
public sealed class Developer : Employee
{
public override decimal CalculateSalary() => 8000;
}
abstract
enforces implementation in derived classes.sealed
prevents unintended inheritance.Use
virtual
to allow extensibility when needed.
🧾 4. Using record
for Immutability and Modeling
public record Product(string Name, decimal Price);
Perfect for DDD, DTOs, event modeling, or value objects.
Combine with
with
expressions:
var updated = product with { Price = 99.90M };
Eliminates boilerplate code and promotes immutability.
🧰 5. Object-Oriented Design with Primary Constructors (C# 12)
public class Order(int number, Customer customer)
{
public void Confirm()
=> Console.WriteLine($"Order {number} confirmed.");
}
Cleaner syntax for encapsulated models.
Great for microservices, use cases, and rich domain models.
🔒 6. Using sealed
for Code Integrity
public sealed class PaymentProcessor
{
public void Process() => Console.WriteLine("Processing...");
}
Avoids unintended inheritance.
Recommended for domain services or sensitive operations.
🛡️ 7. OO + Records for Domain Events
public record OrderCreated(Guid OrderId, DateTime CreatedAt);
Immutable by design.
Fits perfectly into event-driven architectures (EDA).
✅ Conclusion
Object-Oriented Programming remains extremely valuable. When combined with modern .NET and C# features, it becomes even more powerful and expressive.
Key takeaways:
Use
record
for immutability and value models.Apply
required
+init
for safe and immutable construction.Protect domain models with
sealed
andabstract
.Use
interfaces
andpolymorphism
for scalable architecture.
By embracing these practices, you’ll build cleaner, more maintainable, and more testable software with .NET.
🤝 Let's Connect
If you're working with modern .NET and want to master architecture, C#, DevOps, or system interoperability, feel free to reach out:
✍️ Medium
💻 Dev.to
📬 Email: contato@dopme.io