Skip to content
Educora
Intermediate20 min6 / 16

Classes, properties, constructors and records

Bundle data and behaviour together: classes, objects, properties, constructors, primary constructors and record types.

Check yourself
In this lesson you will learn
  • Explain classes and objects and create objects with new
  • Protect data with properties, private set, init and required
  • Write ordinary and primary constructors
  • Use record types and the with expression

You are writing a banking app: every account has an owner and a balance, you can deposit and withdraw money, and the balance must never go negative. For thousands of accounts, separate variables and methods would quickly become a mess. C# is an object-oriented language: data and the methods that work with it are bundled in a class, and then you create as many objects from that class as you need.

Class and object

A class is a blueprint for objects: it describes what data each object will have and what it can do. An object is a concrete instance built from that blueprint with the new keyword. In a file that uses top-level statements, classes are written after the statements, at the end of the file.

C#
var account = new BankAccount("Leyla");
account.Deposit(100);
account.Withdraw(30);
account.Withdraw(500);
Console.WriteLine($"{account.Owner}: {account.Balance} AZN");
var other = new BankAccount("Elvin");
Console.WriteLine($"{other.Owner}: {other.Balance} AZN");

class BankAccount
{
    public string Owner { get; }
    public decimal Balance { get; private set; }

    public BankAccount(string owner)
    {
        Owner = owner;
    }

    public void Deposit(decimal amount) => Balance += amount;
    public void Withdraw(decimal amount)
    {
        if (amount <= Balance) Balance -= amount;
        else Console.WriteLine("Not enough money!");
    }
}
Expected output
Not enough money!
Leyla: 70 AZN
Elvin: 0 AZN
TermMeaningIn the example
Classthe blueprint for objectsBankAccount
Objectan instance made from a classaccount, other
Propertya piece of the object's data with controlled reading and writingBalance
Methodsomething the object can doDeposit()
Constructora special method that runs when an object is createdBankAccount(string owner)

A constructor has the same name as its class and no return type. When you write new BankAccount("Leyla"), the object is created and the constructor is called immediately. account and other come from the same class, but each has its own balance — objects are independent of each other.

Properties and encapsulation

A public member can be seen from anywhere, while a private member is only available inside the class. The property Balance { get; private set; } can be read from outside, but only the class's own methods can change it. If you write account.Balance = 1000000;, the compiler reports error CS0272. Protecting data like this is called encapsulation: the balance changes only through the rules in Deposit and Withdraw.

You can also create an object with an object initializer: properties get their values inside curly braces. init allows a property to be set only while the object is being created, and required demands that it must be filled in. A property whose body is written with => is a computed property: its value is recalculated every time.

C#
var phone = new Product { Name = "Phone", Price = 450m, Stock = 3 };
var cable = new Product { Name = "Cable", Price = 12m };

Console.WriteLine($"{phone.Name}: {phone.TotalValue} AZN, in stock: {phone.InStock}");
Console.WriteLine($"{cable.Name}: {cable.TotalValue} AZN, in stock: {cable.InStock}");

phone.Stock--;
Console.WriteLine($"{phone.Name} left: {phone.Stock}");

class Product
{
    public required string Name { get; init; }
    public decimal Price { get; init; }
    public int Stock { get; set; }

    public decimal TotalValue => Price * Stock;
    public bool InStock => Stock > 0;
}
Expected output
Phone: 1350 AZN, in stock: True
Cable: 0 AZN, in stock: False
Phone left: 2
Writing new Product { Price = 5m } without Name gives error CS9035.

Primary constructors

Since C# 12 you can write the constructor's parameters right after the class name — this is a primary constructor. The parameters are visible in all members of the class, so there is no need for a separate constructor. In the example below, the ToString method defines how the object looks as text: Console.WriteLine(hero) calls exactly that. You will learn about the word override in the next lesson.

C#
var hero = new Player("Aysel");
hero.GainXp(250);
Console.WriteLine(hero);
hero.GainXp(80);
Console.WriteLine(hero);

class Player(string name)
{
    public int Level { get; private set; } = 1;
    public int Xp { get; private set; }

    public void GainXp(int amount)
    {
        Xp += amount;
        Level = 1 + Xp / 100;
    }

    public override string ToString() => $"{name}: level {Level}, {Xp} XP";
}
Expected output
Aysel: level 3, 250 XP
Aysel: level 4, 330 XP

Records: types for data

Sometimes an object only carries data: the coordinates of a point, the date and total of an order. For such cases C# has records. record Point(int X, int Y); creates, in one line, the properties, a constructor, a readable ToString and comparison by value. A record's properties cannot be changed, but the with expression makes a new copy with some properties different.

C#
var p1 = new Point(3, 4);
var p2 = new Point(3, 4);
var p3 = p1 with { Y = 10 };

Console.WriteLine(p1);
Console.WriteLine(p3);
Console.WriteLine(p1 == p2);

var c1 = new PointClass(3, 4);
var c2 = new PointClass(3, 4);
Console.WriteLine(c1 == c2);

record Point(int X, int Y);

class PointClass(int x, int y)
{
    public int X => x;
    public int Y => y;
}
Expected output
Point { X = 3, Y = 4 }
Point { X = 3, Y = 10 }
True
False
Two records with equal values are equal; two ordinary objects are equal only if they are the same object.

Key points

  • A class is a blueprint; an object is a concrete instance created with new.
  • A constructor runs when an object is created; a primary constructor's parameters follow the class name.
  • private set, init and required protect data — this is encapsulation.
  • Classes are reference types: two variables can point to the same object.
  • A record is for immutable data: comparison by value, a ready ToString and with.

Check yourself

10 questions. Every correct answer earns XP.

1 / 10
In the bank example, why did account.Withdraw(500) not change the balance?