C# is a fully object-oriented language. Classes define data and behavior; interfaces specify contracts; inheritance enables code reuse.

Classes and Objects

  class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public virtual void Introduce()
    {
        Console.WriteLine($"I am {Name}, age {Age}");
    }
}

var alice = new Person("Alice", 30);
alice.Introduce();
  

Inheritance and Override

  class Employee : Person
{
    public string Department { get; set; }

    public Employee(string name, int age, string dept)
        : base(name, age)
    {
        Department = dept;
    }

    public override void Introduce()
    {
        base.Introduce();
        Console.WriteLine($"Department: {Department}");
    }
}

new Employee("Bob", 28, "Engineering").Introduce();
  

Interfaces

  interface IDrawable
{
    void Draw();
}

interface IResizable
{
    void Resize(double factor);
}

class Rectangle : IDrawable, IResizable
{
    public double Width { get; set; }
    public double Height { get; set; }

    public void Draw() => Console.WriteLine($"Drawing {Width}x{Height} rectangle");
    public void Resize(double factor)
    {
        Width *= factor;
        Height *= factor;
    }
}
  

Abstract Classes

  abstract class Shape
{
    public abstract double Area();
    public void Describe() => Console.WriteLine($"Area: {Area():F2}");
}

class Circle : Shape
{
    public double Radius { get; set; }
    public override double Area() => Math.PI * Radius * Radius;
}
  

Access Modifiers

Modifier Scope
public Anywhere
private Same class only
protected Class and derived classes
internal Same assembly

Use the most restrictive modifier that still allows necessary access.

Sealed Classes and Methods

  public sealed class FinalService { }  // cannot inherit

public class Base
{
    public virtual void Process() { }
}

public class Derived : Base
{
    public sealed override void Process() { }  // no further override
}
  

Seal classes not designed for inheritance; seal overrides to prevent further specialization.

Structs vs Classes

  public readonly struct Point
{
    public double X { get; init; }
    public double Y { get; init; }

    public double DistanceTo(Point other) =>
        Math.Sqrt(Math.Pow(X - other.X, 2) + Math.Pow(Y - other.Y, 2));
}
  

Use structs for small, immutable value types (coordinates, colors). Use classes for identity-based objects with behavior.

Composition Over Inheritance

  public interface ILogger { void Log(string message); }

public class OrderService
{
    private readonly ILogger _logger;
    public OrderService(ILogger logger) => _logger = logger;

    public void PlaceOrder(Order order)
    {
        _logger.Log($"Order {order.Id} placed");
    }
}
  

Favor injecting behavior over deep inheritance hierarchies.

Polymorphism Example

  ILogger logger = new FileLogger("app.log");
logger = new ConsoleLogger();  // swap implementation
logger.Log("Same interface, different behavior");
  

Common Pitfalls

  • Deep inheritance trees — hard to maintain; prefer interfaces and composition.
  • Public fields instead of properties — breaks encapsulation and data binding.
  • Not calling base in overridden methods when base behavior is still needed.