Skip to content

Class in C#

A class is a user-defined type that groups together data (fields and properties) and behaviour (methods) into one unit. It is the most important building block in C#: almost everything you write, from a console program to an ASP.NET Core controller, lives inside a class.

Think of a class as the blueprint of a house. The blueprint isn't a house; it describes how every house of that design looks. From one blueprint you can build many real houses, each with its own colour and owner. In C#, the blueprint is the class, and each house built from it is an object.

The parts of a class

MemberWhat it isExample
FieldA variable that stores the object's data, usually privateprivate decimal _balance;
PropertyControlled access to data, with get and/or setpublic string Holder { get; }
ConstructorSpecial method that runs when an object is created, to set its starting valuespublic BankAccount(string holder) { ... }
MethodAn action the object can performpublic void Deposit(decimal amount)
Static memberBelongs to the class itself, shared by all objectspublic static int TotalAccounts
OthersEvents, indexers, nested types, operatorspublic event EventHandler Changed;

A simple class

The smallest useful class just holds some data in properties and has a method:

public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; } = string.Empty;
    public int Age { get; set; }
    public string Mobile { get; set; } = string.Empty;

    // Constructor: runs when we write "new Student(...)"
    public Student(int studentId, string name, int age, string mobile)
    {
        StudentId = studentId;
        Name = name;
        Age = age;
        Mobile = mobile;
    }

    public void PrintDetails()
    {
        Console.WriteLine($"{StudentId}: {Name}, {Age} years, {Mobile}");
    }
}

// Creating objects (instances) of the class
var riya = new Student(1, "Riya", 21, "9876543210");
var aman = new Student(2, "Aman", 22, "9123456780");
riya.PrintDetails();
aman.PrintDetails();
Output
1: Riya, 21 years, 9876543210
2: Aman, 22 years, 9123456780

One class, two objects, each with its own data. The new keyword creates an object in memory and calls the constructor.

A realistic class: a bank account

Real classes do more than hold data: they protect it. A bank account balance must never be changed directly from outside, only through Deposit and Withdraw, which check the rules. This is encapsulation, one of the pillars of object-oriented programming.

public class BankAccount
{
    // Field: private, so no code outside the class can change it directly
    private decimal _balance;

    // Static property: one value shared by ALL accounts
    public static int TotalAccounts { get; private set; }

    // Read-only properties: set once in the constructor
    public string AccountNumber { get; }
    public string Holder { get; }

    // Computed property: read-only view of the private field
    public decimal Balance => _balance;

    // Constructor with an optional parameter
    public BankAccount(string accountNumber, string holder, decimal openingBalance = 0)
    {
        AccountNumber = accountNumber;
        Holder = holder;
        _balance = openingBalance;
        TotalAccounts++;
    }

    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Deposit must be positive.");
        _balance += amount;
    }

    public void Withdraw(decimal amount)
    {
        if (amount > _balance)
            throw new InvalidOperationException(
                $"Insufficient balance in {AccountNumber}. Available: {_balance}");
        _balance -= amount;
    }

    // Override the ToString method inherited from System.Object
    public override string ToString() => $"{AccountNumber} | {Holder} | Balance: {_balance}";
}

Using it:

var account1 = new BankAccount("SB-1001", "Asha Rao", 5000);
var account2 = new BankAccount("SB-1002", "Ravi Kumar");      // opening balance defaults to 0

account1.Deposit(2500);
account2.Deposit(1000);

Console.WriteLine(account1);
Console.WriteLine(account2);

try
{
    account2.Withdraw(5000);
}
catch (InvalidOperationException ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}

Console.WriteLine($"Accounts opened: {BankAccount.TotalAccounts}");
Output
SB-1001 | Asha Rao | Balance: 7500
SB-1002 | Ravi Kumar | Balance: 1000
Error: Insufficient balance in SB-1002. Available: 1000
Accounts opened: 2
  • _balance is private: account1._balance = 1000000; does not compile. The only way to change money is through methods that enforce the rules.
  • Balance exposes the value read-only.
  • AccountNumber and Holder have only get, so they can be set in the constructor but never changed afterwards.
  • TotalAccounts is static: it is read through the class name (BankAccount.TotalAccounts), not through an object, and counts every account ever created.
  • Overriding ToString() controls what Console.WriteLine(account1) prints.

Classes are reference types

A variable of a class type doesn't hold the object itself, but a reference (address) to it. Copying the variable copies the reference, so both variables point to the same object:

BankAccount sameAccount = account1;     // no new object is created
sameAccount.Deposit(500);

Console.WriteLine($"account1 balance after depositing through sameAccount: {account1.Balance}");
Console.WriteLine($"Same object? {ReferenceEquals(account1, sameAccount)}");
Output
account1 balance after depositing through sameAccount: 8000
Same object? True

The deposit was made through sameAccount, but account1 shows it too, because it's one account with two names. This behaviour is important when you pass objects to methods; see Parameter Passing Techniques.

Class vs object

ClassObject
A blueprint or templateA real instance built from the blueprint
Declared once with the class keywordCreated many times with new
Describes which data and methods existHolds actual values (Asha's balance is 7500)
Takes no memory for instance data by itselfEach object takes memory on the heap
BankAccountaccount1, account2

Read more about objects in Object in C#.

Points to remember

  • A class is a reference type; its objects live on the managed heap and are cleaned up by the garbage collector.
  • A top-level class without an access modifier is internal by default (visible only inside the same project). Members without a modifier are private.
  • Every class inherits from System.Object, which is why every object has ToString(), Equals() and GetHashCode().
  • If you don't write any constructor, C# adds a public parameterless one. Once you write your own, that default constructor is no longer generated.
  • A class can inherit from only one class, but implement many interfaces.
  • Special kinds of classes: abstract, sealed, static and partial.

Class vs struct (quick comparison)

classstruct
TypeReference typeValue type
AssignmentCopies the reference (shared object)Copies the whole value
InheritanceSupportedNot supported (only interfaces)
Can be nullYesNo (unless Nullable<T>)
Use forEntities and services with behaviour: customers, orders, accountsSmall immutable values: points, money amounts, coordinates

Interview questions

1. What is a class in C#?

A user-defined reference type that combines data (fields, properties) and behaviour (methods, events) into a single unit. Objects are created from it with new.

2. What is the default access modifier of a class?

internal for a top-level class. Members of a class are private by default.

3. What is the difference between a field and a property?

A field is a variable that stores data. A property wraps access to data with get/set accessors, so it can validate values, be read-only, or be computed, while looking like a field to the caller.

4. What is a static member?

A member that belongs to the class rather than to an object. All objects share it, and it is accessed through the class name, like BankAccount.TotalAccounts.

5. What happens when you assign one object variable to another?

Only the reference is copied; both variables refer to the same object, so a change through one is visible through the other.

Summary

  • A class is a blueprint; objects are instances created with new.
  • Classes contain fields, properties, constructors, methods and static members.
  • Keep data private and change it only through methods that enforce the rules (encapsulation).
  • Classes are reference types: assigning a variable shares the same object.
  • Every class derives from System.Object; top-level classes are internal by default.