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 initialisationAccess 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 methodoverride= this method replaces the parent's versionsealed= 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); // TrueStructs 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
recordfor data objects that do not need mutation. - Use
initinstead ofsetwhen 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.