Comprehensive Guide to C# and .NET Core OOP Concepts and Language Features

Comprehensive Guide to C# and .NET Core OOP Concepts

Class

  • A class is a blueprint for creating objects that encapsulate both data and behavior.
  • Access Modifiers: public, internal, abstract, sealed control visibility and inheritance.
  • Static Classes: Cannot be instantiated, contain only static members.
  • Partial Classes: Split across files using partial keyword for better organization.
public class Car
{
    public string Model;
    public void Drive() => Console.WriteLine($"{Model} is driving.");
}

Analogy: A car blueprint used to build many actual cars.

Benefits: Reusability, Encapsulation, Abstraction, Inheritance

Object

  • An object is an instance of a class.
  • Managed by Garbage Collector for automatic memory cleanup.
  • Boxing/Unboxing allows value types to be treated as objects (with some performance cost).
Car car1 = new Car { Model = "Toyota" };
car1.Drive();  // Output: Toyota is driving.

Analogy: A specific Toyota car built from the Car blueprint.

Benefits: Real-world representation, runtime allocation, behavior encapsulation

Encapsulation

  • Binds data and methods into a single unit and restricts direct access.
  • Use properties with getters/setters instead of public fields.
  • Fine-grained access control with accessors.
public class BankAccount
{
    private double balance = 1000;
    public void Deposit(double amount) => balance += amount;
    public double GetBalance() => balance;
}

Analogy: ATM machine—deposit or withdraw money but can't access internals.

Benefits: Data protection, controlled access, maintainability

Abstraction

  • Hides complex internal implementation, exposing only necessary features.
  • Interfaces provide pure abstraction.
  • Abstract classes can include implementations.
  • Encourages loose coupling.
public abstract class Shape
{
    public abstract double GetArea();
}

Analogy: Driving a car without needing to understand how the engine works.

Benefits: Simplifies complex systems, Focus on behavior, Improves modularity

Inheritance

  • A class can inherit fields and methods from another class.
  • Use sealed to prevent inheritance.
  • Single inheritance for classes; multiple inheritance allowed via interfaces.
public class Vehicle
{
    public void Start() => Console.WriteLine("Vehicle started");
}

public class Bike : Vehicle
{
    public void Ride() => Console.WriteLine("Bike is riding");
}

Analogy: A child inherits traits from their parents.

Benefits: Code reuse, classification, extension

Polymorphism

  • The same method behaves differently depending on the object.
  • virtual, override, and new control overriding vs hiding.
  • Interfaces enable polymorphism via multiple implementations.
  • Compile-time (overloading) vs Run-time (overriding).
public class Animal
{
    public virtual void Speak() => Console.WriteLine("Animal sound");
}

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

Analogy: A universal remote controls different devices in unique ways.

Benefits: Flexibility, code reuse, interface-driven design

Inheritance vs Composition

  • Inheritance: “is-a” relationship
  • Composition: “has-a” relationship
  • Favor composition for better flexibility and SRP adherence.
public class Engine
{
    public void Start() => Console.WriteLine("Engine started");
}

public class Car
{
    private Engine engine = new Engine();
    public void StartCar() => engine.Start();
}

Analogy: A car has an engine (composition); a sports car is a type of car (inheritance).

Benefits: Flexibility, reusability via delegation, loose coupling

Constructor and Destructor

  • Constructor: Initializes a new object.
  • Destructor: Cleanup before object destruction.
  • Prefer IDisposable for unmanaged resource cleanup.
public class Person
{
    public string Name;
    public Person(string name) => Name = name;
    ~Person() => Console.WriteLine("Destructor called");
}

Analogy: Setting up a new apartment (constructor), cleaning it when leaving (destructor).

Benefits: Proper initialization, Resource cleanup

Interface and Abstract Class

Interface

  • Declares methods/properties without implementation.
  • Supports multiple inheritance.
public interface IAnimal
{
    void Eat();
}

public class Cow : IAnimal
{
    public void Eat() => Console.WriteLine("Cow eats grass");
}

Abstract Class

  • Can provide both abstract and concrete members.
  • Can include fields and constructors.
public abstract class Animal
{
    public abstract void Eat();
}

Analogy:
Interface: A contract to fulfill.
Abstract class: A partially built system to extend.

Benefits: Extensibility, Code maintainability

Field vs Property vs Const vs Readonly

Concept Modifiable When Set Scope
FieldYesAny timeInstance/Static
PropertyControlled (get/set)Via accessorsInstance/Static
constNoAt compile timeStatic by default
readonlyNoAt declaration or in constructorInstance/Static
public class Server
{
    public const double Pi = 3.14159;   // Constant
    public readonly string HostName;    // Readonly

    public Server(string hostName)
    {
        HostName = hostName;
    }

    private string _name;
    public string Name                  // Property
    {
        get => _name;
        set => _name = value;
    }
}

Indexers

  • Allows object instances to be indexed like arrays.
class SampleCollection
{
    private string[] data = new string[100];

    public string this[int index]
    {
        get => data[index];
        set => data[index] = value;
    }
}

// Usage:
var collection = new SampleCollection();
collection[0] = "Hello";
Console.WriteLine(collection[0]); // Outputs "Hello"

Partial Methods

  • Declared in one part of a partial class and optionally implemented in another.
  • If not implemented, they are removed during compilation (zero overhead).
public partial class MyClass
{
    partial void OnSomethingHappened();

    public void DoWork()
    {
        OnSomethingHappened(); // Will only call if implemented
    }
}

public partial class MyClass
{
    partial void OnSomethingHappened()
    {
        Console.WriteLine("Something happened!");
    }
}

Nested Types

Classes declared inside other classes. Useful for tightly coupling helper types to a containing type without exposing them globally.

public class OuterClass
{
    private class NestedHelper
    {
        public void Help() => Console.WriteLine("Helping...");
    }

    public void UseHelper()
    {
        var helper = new NestedHelper();
        helper.Help();
    }
}

Covariance and Contravariance

Enable flexible type compatibility for generics, mainly with interfaces and delegates.

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings; // Covariance

Action<object> actObject = obj => Console.WriteLine(obj);
Action<string> actString = actObject; // Contravariance

Tuples

Lightweight, unnamed grouping of multiple values.

var person = (Name: "Alice", Age: 30);
Console.WriteLine($"{person.Name} is {person.Age} years old.");

Generics

Write reusable, type-safe code. Constraints can be added for additional safety.

public class Repository<T> where T : class
{
    public void Add(T item) { /*...*/ }
}

Primary Constructors (C# 12)

Compact syntax for declaring and initializing properties via constructor parameters.

public class Point(int X, int Y)
{
    public int X { get; } = X;
    public int Y { get; } = Y;
}

Readonly Fields vs Init-only Properties

readonly fields are set only in constructor. init properties set only at initialization.

public class Server
{
    public readonly string IP;
    public string Name { get; init; }

    public Server(string ip) => IP = ip;
}

Lazy Initialization

Delays object creation until it's accessed.

Lazy<ExpensiveClass> lazyObj = new(() => new ExpensiveClass());
var obj = lazyObj.Value; // Object created here

Expression Trees

Represent code as data—useful in LINQ and dynamic queries.

Expression<Func<int, bool>> expr = x => x > 5;
Console.WriteLine(expr.Body); // Outputs: (x > 5)

Reflection

Inspect and manipulate types at runtime.

var type = typeof(string);
var methods = type.GetMethods();
Console.WriteLine(methods.Length);

Source Generators

Compile-time code generation tool that produces additional source code.

FAQs and Conceptual Clarifications

What is the difference between a class and an object?

  • Class: A blueprint or template defining properties, methods, and behaviors of a type.
  • Object: An instance of a class; a concrete entity created in memory with actual data.
  • Example: If Car is a class, then var myCar = new Car() is an object.

How does encapsulation protect data in OOP?

Encapsulation hides internal data and implementation details from outside access, exposing only what’s necessary through public methods or properties. This prevents unauthorized or accidental modification, enhancing security and maintainability.

Explain the difference between abstraction and encapsulation.

  • Abstraction: Focuses on exposing only relevant features and hiding complex implementation (what an object does).
  • Encapsulation: Focuses on hiding the internal state and requiring all interaction to be performed through an object’s methods (how it is done).

Can you inherit from multiple classes in C#? If not, what is the workaround?

No, C# does not support multiple inheritance for classes. The workaround is to use interfaces, which allow a class to implement multiple contracts without inheriting implementation.

What are the differences between const and readonly?

Feature const readonly
Value assignedAt compile timeAt runtime (in constructor)
Can change?NoNo, after initialization
StorageStatic by defaultInstance or static
UseFor compile-time constantsFor values known only at runtime

How does polymorphism benefit software design?

Polymorphism allows one interface to represent different underlying forms (data types). It enables flexible and extensible code by allowing objects to be treated as instances of their parent class or interface while invoking the appropriate overridden method at runtime.

When would you prefer composition over inheritance?

Prefer composition when you want to build complex functionality by combining simpler objects, or when you want to avoid the tight coupling and fragility that can come with deep inheritance hierarchies. Composition favors flexibility and reusability.

What is the purpose of an interface?

An interface defines a contract or set of methods and properties that implementing classes must provide, without dictating how they are implemented. It enables polymorphism and loose coupling by separating the definition from the implementation.

How do you implement lazy initialization?

Lazy<MyClass> lazyObj = new(() => new MyClass());
MyClass obj = lazyObj.Value; // Object created on first access

What are partial classes and partial methods?

  • Partial classes: Allow splitting the definition of a class across multiple files, useful in large projects or auto-generated code scenarios.
  • Partial methods: Optional method declarations in partial classes where the implementation can be provided in another part. If not implemented, calls are removed at compile time.

Comments

Popular posts from this blog

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Promises in Angular