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

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

Class

class is a blueprint for creating objects that encapsulate both data and behavior.

Key Points

  • 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.

Example

public class Car

{

    public string Model;

 

    public void Drive() => Console.WriteLine($"{Model} is driving.");

}

Analogy

car blueprint used to build many actual cars.

Benefits

  • Reusability
  • Encapsulation of data and logic
  • Supports abstraction and inheritance

 

Object

An object is an instance of a class.

Key Points

  • Managed by Garbage Collector for automatic memory cleanup.
  • Boxing/Unboxing allows value types to be treated as objects (with some performance cost).

Example

Car car1 = new Car { Model = "Toyota" };

car1.Drive();  // Output: Toyota is driving.

Analogy

A specific Toyota car built from the Car blueprint.

Benefits

  • Enables real-world use of classes
  • Memory allocated at runtime
  • Enables interaction between data and methods

 

Encapsulation

Encapsulation binds data and methods into a single unit and restricts direct access.

Key Points

  • Use properties with getters/setters instead of public fields.
  • Fine-grained access control with accessors.

Example

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

  • Protects data integrity
  • Controlled access
  • Simplifies system complexity

 

Abstraction

Abstraction hides complex internal implementation, exposing only necessary features.

Key Points

  • Interfaces provide pure abstraction.
  • Abstract classes can include implementations.
  • Encourages loose coupling.

Example

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 what an object does
  • Improves modularity and readability

 

Inheritance

A class can inherit fields and methods from another class.

Key Points

  • Use sealed to prevent inheritance.
  • Single inheritance for classes; multiple inheritance allowed via interfaces.

Example

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
  • Hierarchical classification
  • Simplifies extensions

 

Polymorphism

The same method behaves differently depending on the object.

Key Points

  • virtual, override, and new control overriding vs hiding.
  • Interfaces enable polymorphism via multiple implementations.
  • Compile-time (overloading) vs run-time (overriding).

Example

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
  • Simplifies interface-based design
  • Scalability

 

Inheritance vs Composition

  • Inheritance: “is-a” relationship
  • Composition: “has-a” relationship
  • Favor composition for better flexibility and adherence to SRP (Single Responsibility Principle).

Composition Example

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

  • Better flexibility
  • Reuse via delegation
  • Avoids tight coupling

 

Constructor and Destructor

  • Constructor: Initializes a new object.
  • Destructor: Cleanup before object destruction.
  • Prefer IDisposable for unmanaged resource cleanup.

Example

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 object setup
  • Helps cleanup resources

 

Interface and Abstract Class

Interface

  • Declares methods/properties without implementation.
  • Supports multiple inheritance.

Abstract Class

  • Can provide abstract and concrete members.
  • Can have fields.

Interface Example

public interface IAnimal

{

    void Eat();

}

 

public class Cow : IAnimal

{

    public void Eat() => Console.WriteLine("Cow eats grass");

}

Abstract Class Example

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

Field

Yes

Any time

Instance/static

Property

Controlled (get/set)

Via get/set

Instance/static

const

No

Compile time only

Static by default

readonly

No

Declaration or constructor

Instance/static

Example

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 accessing class data with array-like syntax.

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

Partial methods allow you to declare a method signature in one part of a partial class and optionally implement it in another. If the implementation is missing, calls to the method are removed at compile time—no overhead.

public partial class MyClass

{

    partial void OnSomethingHappened();

 

    public void DoWork()

    {

        // Call the partial method if implemented

        OnSomethingHappened();

    }

}

 

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

Generics with out (covariance) and in (contravariance) enable flexible type compatibility, mainly for interfaces and delegates.

IEnumerable<string> strings = new List<string>();

IEnumerable<object> objects = strings; // Covariance: IEnumerable<out T>

 

Action<object> actObject = obj => Console.WriteLine(obj);

Action<string> actString = actObject;  // Contravariance: Action<in T>

 

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. You can add constraints for type safety.

public class Repository<T> where T : class

{

    public void Add(T item) { /*...*/ }

}

 

Primary Constructors (C# 12)

Compact syntax for declaring and initializing class 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 can only be assigned during declaration or in the constructor.
  • init properties can only be set during object initialization.

public class Server

{

    public readonly string IP;

    public string Name { get; init; }

 

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

}

 

Lazy Initialization

Delays expensive object creation until actually needed.

Lazy<ExpensiveClass> lazyObj = new(() => new ExpensiveClass());

var obj = lazyObj.Value; // Object created here

 

Expression Trees

Represent code as data, useful for dynamic query generation (e.g., LINQ providers).

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 that creates additional source files to optimize or simplify code.

 

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 a specific car like 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 assigned

At compile time

At runtime (in constructor)

Can change?

No

No, after initialization

Storage

Static by default

Instance or static

Use

For compile-time constants

For 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 initialization delays the creation of an object until it is needed, improving performance.

Example:

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

Promises in Angular

Mastering Your Angular Workflow: Essential CLI Commands for Efficient Development

Observables in Angular