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
A 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
A 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
Post a Comment