C# Classes & Objects

C# is a class-based, object-oriented language. Classes define blueprints; objects are instances of those blueprints.

Basic Class

CSHARP
class Book
{
    // Properties (data)
    public string Title { get; set; }
    public string Author { get; set; }
    public int Pages { get; set; }

    // Constructor (initialises the object)
    public Book(string title, string author, int pages)
    {
        Title = title;
        Author = author;
        Pages = pages;
    }

    // Method (behaviour)
    public string Summary()
    {
        return $"{Title} by {Author} ({Pages} pages)";
    }
}

// Creating an object
var book = new Book("Palpasa Cafe", "Narayan Wagle", 312);
Console.WriteLine(book.Summary());
// "Palpasa Cafe by Narayan Wagle (312 pages)"

Auto-Properties

Shorthand for simple properties — C# creates the backing field automatically:

CSHARP
public string Title { get; set; }          // read-write
public int Age { get; private set; }       // read-only from outside
public string Name { get; init; }          // set only during initialisation

Access Modifiers

Modifier Class Subclass Assembly (project) World
public ✅ ✅ ✅ ✅
protected ✅ ✅ ❌ ❌
internal ✅ ✅ ✅ ❌
private ✅ ❌ ❌ ❌

Default is private for members and internal for classes.

Inheritance

CSHARP
class Animal
{
    public string Name { get; set; }
    public virtual void Speak() => Console.WriteLine("...");
}

class Dog : Animal
{
    public override void Speak() => Console.WriteLine("Woof!");
}

var rex = new Dog { Name = "Rex" };
rex.Speak(); // "Woof!"
  • virtual = subclasses can override this method
  • override = this method replaces the parent's version
  • sealed = subclasses cannot override further

Interfaces

Interfaces define a contract — a set of methods and properties a class must implement:

CSHARP
interface IShape
{
    double Area();
    string Name { get; }
}

class Circle : IShape
{
    public double Radius { get; set; }
    public string Name => "Circle";
    public double Area() => Math.PI * Radius * Radius;
}

class Rectangle : IShape
{
    public double Width { get; set; }
    public double Height { get; set; }
    public string Name => "Rectangle";
    public double Area() => Width * Height;
}

Convention: prefix interface names with I (IShape, IRepository).

Records (C# 9+)

Immutable data carriers — ideal for DTOs and value objects:

CSHARP
record Person(string Name, int Age);
record Point(double X, double Y);

var ram = new Person("Ram", 22);
Console.WriteLine(ram); // Person { Name = Ram, Age = 22 }

// Records support equality out of the box
var ram2 = new Person("Ram", 22);
Console.WriteLine(ram == ram2); // True

Structs vs Classes vs Records

Feature Struct Class Record
Type Value Reference Reference
Inheritance ❌ ✅ ✅
Mutable ✅ ✅ ❌ (default)
Use for Small data Behaviour Data transfer

Rule of thumb: start with class, use record for DTOs, use struct only for small, immutable value types.

Tips

  • Prefer record for data objects that do not need mutation.
  • Use init instead of set when properties should only be set during construction.
  • Keep classes small and focused — one responsibility per class.
  • Use interfaces for loose coupling — depend on abstractions, not concrete classes.

Next: collections — lists, dictionaries, and more.