3. Object-Oriented Programming


The Four Pillars of OOP


┌─────────────────────────────────────────────────────────────────────────────┐
│                    OBJECT-ORIENTED PROGRAMMING                              │
│                                                                             │
│  ┌────────────────┐  ┌────────────────┐  ┌──────────────┐  ┌──────────────┐ │
│  │ ENCAPSULATION  │  │  ABSTRACTION   │  │  INHERITANCE │  │ POLYMORPHISM │ │
│  │────────────────│  │────────────────│  │──────────────│  │──────────────│ │
│  │ Hide details   │  │ Hide complex   │  │  Reuse code  │  │ One interface│ │
│  │ Use properties │  │ Show essential │  │  Extend types│  │ Many forms   │ │
│  │ Access control │  │ Interfaces     │  │  Base/derived│  │ Overriding   │ │
│  └────────────────┘  └────────────────┘  └──────────────┘  └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘

1. Classes and Objects

Class Definition Anatomy

Class Components:

  • Fields - Private data storage

  • Properties - Controlled access to data

  • Methods - Actions/behavior

  • Constructors - Object initialization

  • Events - Notifications

Object Creation (new keyword)

Reference Semantics

Memory Diagram:

this Keyword

Object Initializers (C# 3.0+)


2. Structs

Struct vs Class

Feature
Struct
Class

Type

Value type

Reference type

Storage

Stack (usually)

Heap

Default

Cannot be null

Can be null

Inheritance

Cannot inherit from struct

Can inherit from class

Constructor

Must initialize all fields

Can have parameterless constructor

Performance

Faster for small data

Slower (heap allocation)

Copying

Copies all data

Copies reference

When to use

Small, immutable data (< 16 bytes)

Complex objects, inheritance needed

Struct Declaration

Struct Limitations

readonly struct (C# 7.2+)

ref struct (C# 7.2+)

When to Use Struct vs Class

Use Struct When:

  • ✅ Small data (< 16 bytes)

  • ✅ Immutable (readonly)

  • ✅ Value semantics needed

  • ✅ Short-lived

  • Examples: Point, Color, DateTime

Use Class When:

  • ✅ Large objects

  • ✅ Inheritance needed

  • ✅ Reference semantics needed

  • ✅ Long-lived

  • Examples: Person, Order, Repository


3. Constructors

Default Constructor

Parameterized Constructor

Constructor Overloading

Constructor Chaining (this)

Copy Constructor Pattern

Static Constructor

Static Constructor Rules:

  • No access modifiers

  • No parameters

  • Called automatically before any static members accessed

  • Called only once

  • Cannot be called directly

Private Constructor (Singleton Pattern)

Primary Constructors (C# 12.0+)


4. Destructors (Finalizers)

Syntax

When Destructors Run

  • Called by Garbage Collector (GC) when object is about to be collected

  • Timing is non-deterministic (you don't know when)

  • Object survives at least one more GC cycle

Destructor vs Dispose

Feature
Destructor (~)
Dispose()

When runs

GC time (unpredictable)

Immediately when called

Guaranteed

No (may never run)

Yes (if called)

Use for

Unmanaged resources cleanup

Unmanaged resources cleanup

Performance

Slower (two GC cycles)

Faster

Recommended

Only if needed

Yes, implement IDisposable

Why to Avoid Destructors

Best Practice: Use IDisposable pattern, not destructors. Only add destructor if you have unmanaged resources AND user might forget to call Dispose().


5. Properties

Full Property Syntax

Auto-Implemented Properties (C# 3.0+)

Property Access Levels

Read-Only Properties

Computed Properties

Init-Only Setters (C# 9.0+)

required Properties (C# 11.0+)

Property vs Field Comparison

Feature
Field
Property

Syntax

public int age;

public int Age { get; set; }

Encapsulation

Direct access

Controlled access

Validation

No

Yes (in setter)

Debugging

Can't set breakpoint

Can set breakpoint

Interface

Cannot be in interface

Can be in interface

Virtual

Cannot override

Can be virtual/override

Recommended

Private only

Public API

Best Practice: Always use properties for public API, not fields.

Expression-Bodied Properties (C# 6.0+)


6. Access Modifiers

Access Levels

Modifier
Accessible From

public

Anywhere

private

Same class only

protected

Same class + derived classes

internal

Same assembly

protected internal

Same assembly OR derived classes

private protected

Same assembly AND derived classes (C# 7.2+)

Visual Accessibility Diagram

Examples

Default Access Levels


7. Methods

Method Signature

Method Overloading

Same name, different parameters

Overloading Rules:

  • Must differ in: number of parameters, types of parameters, or parameter order

  • Return type alone is NOT enough

  • Parameter names don't matter

Method Parameters

Value Parameters (Default)

ref Parameters

ref Rules:

  • Must initialize before passing

  • Caller must use ref keyword

  • Method can read and write

out Parameters

out Rules:

  • No need to initialize before passing

  • Must be assigned in method before returning

  • Caller must use out keyword

in Parameters (C# 7.2+)

in Rules:

  • Read-only reference

  • Avoids copying large structs

  • Caller can optionally use in keyword

params Parameters

Optional Parameters (C# 4.0+)

Rules:

  • Optional parameters must be last

  • Must have default value (compile-time constant)

Named Arguments (C# 4.0+)

Expression-Bodied Methods (C# 6.0+)

Local Functions (C# 7.0+)

Static Local Functions (C# 8.0+)

When to Use:

  • Prevent accidental capture of outer variables

  • Better performance (no closure allocation)


8. The Four Pillars of OOP

Pillar 1: Encapsulation

Definition: Hide implementation details, expose only what's necessary.

Benefits:

  • Control access to data

  • Validate inputs

  • Change implementation without breaking external code

  • Hide complexity

Pillar 2: Abstraction

Definition: Show only essential features, hide complex implementation.

Abstract Classes

Interfaces

Multiple Interface Implementation

Explicit Interface Implementation

Default Interface Methods (C# 8.0+)

Static Abstract Members (C# 11.0+)

Abstract Class vs Interface

Feature
Abstract Class
Interface

Can have

Abstract + concrete members

Abstract members (+ default C# 8.0+)

Fields

Yes

No

Constructors

Yes

No

Access modifiers

Any

Public only (implicitly)

Inheritance

Single (one base class)

Multiple (many interfaces)

When to use

Shared code, common base

Contract, multiple inheritance

Decision Guide:

  • Use abstract class when: Classes share common code, need fields/constructors

  • Use interface when: Define contract, need multiple inheritance, no shared code

Pillar 3: Inheritance

Definition: Create new classes from existing ones, reusing code.

Single Inheritance

Multiple Inheritance (Interfaces)

base Keyword

Calling Base Constructors

sealed Classes (Prevent Inheritance)

When to use sealed:

  • Prevent further inheritance

  • Security reasons

  • Performance (compiler optimizations)

Inheritance Hierarchy Example

Pillar 4: Polymorphism

Definition: One interface, many implementations.

Compile-Time Polymorphism (Method Overloading)

Runtime Polymorphism (Method Overriding)

virtual, override, sealed

Method Hiding with new

virtual / override / new Summary:

Keyword
Purpose
Polymorphic?

virtual

Mark method as overridable

Yes

override

Replace base implementation

Yes

new

Hide base method

No

sealed override

Override but prevent further overrides

Yes


9. Static Members

Static Fields

Static Methods

Static Constructors

Static Classes

When to Use Static Class:

  • Utility/helper methods (Math, Console, Convert)

  • Extension methods (must be in static class)

  • Constants and global state

  • No state needed

Static vs Instance:

Feature
Instance
Static

Creation

new ClassName()

N/A

Access

Through instance

Through class name

this

Can use

Cannot use

State

Per object

Shared

Inheritance

Yes

No (static class)


10. Partial Classes (C# 2.0+)

Split Class Definition

Use Cases

  1. Code Generation

  1. Large Classes

Partial Methods (C# 3.0+)

Rules:

  • Must return void

  • Cannot have out parameters

  • Implicitly private

  • Implementation is optional (if not implemented, call is removed by compiler)

Partial Properties (C# 13.0+)


11. Extension Methods (C# 3.0+)

Syntax

Rules and Limitations

Common Use Cases


12. Nested Classes

Inner Classes

Access to Outer Class Members

When to Use Nested Classes

Use When:

  • ✅ Class is only used by outer class

  • ✅ Want to hide implementation details

  • ✅ Logically belongs to outer class

  • Examples: Node in LinkedList, Enumerator in collection

Don't Use When:

  • ❌ Class might be useful elsewhere

  • ❌ Makes code harder to read

  • ❌ Just for organization (use namespace instead)


13. Anonymous Types (C# 3.0+)

Syntax

Use with LINQ

Limitations

When to Use:

  • ✅ LINQ projections

  • ✅ Temporary data structures within a method

  • ✅ Grouping related data for short-term use

Don't Use:

  • ❌ Public API (return types, parameters)

  • ❌ Long-term data storage

  • ❌ When you need methods or constructors


14. Records (C# 9.0+)

Record Classes (Reference Types)

Positional Records

with Expressions (Non-Destructive Mutation)

Value-Based Equality

Record Structs (C# 10.0+)

Record vs Class vs Struct

Feature
Class
Struct
Record (class)
Record struct

Type

Reference

Value

Reference

Value

Storage

Heap

Stack

Heap

Stack

Equality

Reference

Value

Value

Value

Immutability

No (default)

No

Yes (default)

Yes (default)

with

No

No

Yes

Yes

Inheritance

Yes

No

Yes (records only)

No

ToString()

Type name

Type name

All properties

All properties

When to use

Mutable objects

Small, value semantics

Immutable data

Small, immutable value data

When to Use Records

Use Records When:

  • ✅ Immutable data (DTOs, data transfer objects)

  • ✅ Value-based equality needed

  • ✅ POCO (Plain Old CLR Objects)

  • ✅ API models, configuration

Examples:


15. Operator Overloading

Overloadable Operators

Can Overload:

  • Unary: +, -, !, ~, ++, --, true, false

  • Binary: +, -, *, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=

Cannot Overload:

  • =, ., ?:, ??, ->, =>, is, as, new, typeof, sizeof, checked, unchecked

Syntax

Comparison Operators (Must Override in Pairs)

Best Practices


16. Conversion Operators

implicit operator (Automatic Conversion)

explicit operator (Manual Conversion)

When to Use Each

Use implicit When:

  • ✅ Conversion is always safe (no data loss)

  • ✅ Conversion is intuitive

  • ✅ No exceptions will be thrown

  • Examples: int → long, float → double

Use explicit When:

  • ✅ Conversion might lose data

  • ✅ Conversion might throw exception

  • ✅ Conversion is not obvious

  • Examples: double → int, Celsius → Fahrenheit


17. Indexers

Syntax

Multiple Indexers

Overloading Indexers

Read-Only Indexer


Common Pitfalls

1. Forgetting virtual/override

2. Using new Instead of override

3. Not Calling base Constructor

4. Struct Mutability Issues

5. Property vs Field in Interfaces

6. Forgetting to Override Equals and GetHashCode


Best Practices

1. Encapsulation

2. Use Auto-Properties When Possible

3. Prefer Composition Over Inheritance

4. Use Interfaces for Contracts

5. Mark Classes sealed When Not Designed for Inheritance

6. Use Records for Immutable Data

7. Initialize Collections in Constructor or Inline

8. Use Expression-Bodied Members for Simple Properties

9. Validate in Constructors

10. Use readonly for Immutable Fields


Quick Reference: Decision Trees

Should I Use Class, Struct, or Record?

Should I Use Abstract Class or Interface?

Should Method Be virtual?


Guide Complete! This comprehensive OOP guide covers all essential concepts from basic classes to advanced features like records and operator overloading. Ready for printing and study! 📘

Last updated