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.
- 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
partialkeyword 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
sealedto 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, andnewcontrol 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
IDisposablefor 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 |
|---|---|---|---|
| Field | Yes | Any time | Instance/Static |
| Property | Controlled (get/set) | Via accessors | Instance/Static |
| const | No | At compile time | Static by default |
| readonly | No | At declaration or in constructor | Instance/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
partialclass 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
Caris a class, thenvar 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<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