Skip to main content

πŸ“ Lesson 4.2: Introduction to Object-Oriented Programming

C# is an object-oriented language. In this lesson you'll design your own custom types β€” classes β€” that bundle related data and behavior together, the way real-world things do.

🎯 Learning Objectives

By the end of this lesson, you will be able to:

  • Explain the difference between a class and an object
  • Define a class with properties (data) and methods (behavior)
  • Create objects with new and a constructor
  • Understand this and how objects hold their own state
  • See why OOP helps you model real-world problems

Estimated Time: 60 minutes

Project: Design a BankAccount class and use it.

In This Lesson

What Is OOP?

Object-Oriented Programming (OOP) is a way of organizing code around objects β€” self-contained units that bundle together related data and the behavior that acts on it.

Think about a real-world car. It has data (color, current speed, fuel level) and behavior (accelerate, brake, honk). OOP lets you model that in code: a single Car object holds its own data and knows how to act on it.

πŸ“– Definition

Object-Oriented Programming: a style of programming that groups related data and behavior into objects, created from blueprints called classes.

So far your data (variables) and behavior (methods) have been separate. OOP brings them together into tidy, reusable units β€” which is how nearly all real C# programs are structured.

Classes vs. Objects

This is the single most important idea in the lesson, so let's make it concrete.

πŸ’‘ The blueprint analogy

A class is a blueprint. An object is a thing built from that blueprint.

One architectural blueprint for a house (the class) can be used to build many actual houses (the objects). Each house is separate β€” you can paint one blue and another red β€” but all follow the same blueprint.

graph TD A["class Car
(the blueprint)"] --> B["Car object #1
red, 60 mph"] A --> C["Car object #2
blue, 0 mph"] A --> D["Car object #3
black, 30 mph"] style A fill:#eff6ff,stroke:#3b82f6,stroke-width:2px style B fill:#e8f5e9,stroke:#4CAF50,stroke-width:2px style C fill:#e8f5e9,stroke:#4CAF50,stroke-width:2px style D fill:#e8f5e9,stroke:#4CAF50,stroke-width:2px

You define a class once, then create as many objects (also called instances) from it as you need β€” each with its own data.

Your First Class

Let's model a person. A class is declared with the class keyword and, by convention, a PascalCase name:

class Person
{
    // Properties (data each person has)
    public string Name;
    public int Age;
}

Now create objects from that blueprint using the new keyword, and access their data with a dot .:

Person alice = new Person();
alice.Name = "Alice";
alice.Age = 30;

Person bob = new Person();
bob.Name = "Bob";
bob.Age = 25;

Console.WriteLine($"{alice.Name} is {alice.Age}.");   // Alice is 30.
Console.WriteLine($"{bob.Name} is {bob.Age}.");       // Bob is 25.

alice and bob are two separate objects from the same Person class. Changing alice.Age has no effect on bob β€” each object holds its own state.

πŸ’‘ public?

The public keyword means this member is accessible from outside the class (so we can read and set alice.Name). You'll also meet private, which hides a member so only the class's own code can touch it β€” a way to protect an object's internal data.

Properties: An Object's Data

The Name and Age above are simple fields. In real C#, we usually expose data through properties, which look like fields but can control how values are read and written. The short form uses { get; set; }:

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

You use them exactly like fields β€” alice.Name = "Alice"; β€” but properties give you a place to add rules later without changing how callers use them. For example, a property can reject invalid values:

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

    private int _age;                 // backing field (private)
    public int Age
    {
        get { return _age; }
        set
        {
            if (value >= 0)           // 'value' is what the caller assigned
            {
                _age = value;
            }
        }
    }
}

βœ… Why properties?

Properties are the C# convention for exposing data. Start with the simple { get; set; } form; reach for the longer form only when you need validation or extra logic. The keyword value inside a set holds whatever the caller is trying to assign.

Methods: An Object's Behavior

Data is only half of an object. Methods inside a class define what the object can do β€” and they can freely use the object's own properties:

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

    // A method: behavior that uses this object's own data
    public void Introduce()
    {
        Console.WriteLine($"Hi, I'm {Name} and I'm {Age} years old.");
    }

    public bool IsAdult()
    {
        return Age >= 18;
    }
}
Person alice = new Person();
alice.Name = "Alice";
alice.Age = 30;

alice.Introduce();                       // Hi, I'm Alice and I'm 30 years old.
Console.WriteLine(alice.IsAdult());      // True

Notice Introduce uses Name and Age directly β€” because it belongs to the class, it automatically works with that particular object's data. Call alice.Introduce() and it uses Alice's values; a bob.Introduce() would use Bob's.

πŸ’‘ This is the heart of OOP

Data (Name, Age) and behavior (Introduce, IsAdult) live together in one class. The object carries everything it needs. This bundling is called encapsulation.

Constructors

Setting each property one line at a time is tedious. A constructor is a special method that runs when you create an object with new, letting you set up the object in one step. It has the same name as the class and no return type:

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

    // Constructor β€” runs when you write 'new Person(...)'
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }

    public void Introduce()
    {
        Console.WriteLine($"Hi, I'm {Name} and I'm {Age} years old.");
    }
}

Now creating a fully-formed object is a single line:

Person alice = new Person("Alice", 30);
Person bob = new Person("Bob", 25);

alice.Introduce();   // Hi, I'm Alice and I'm 30 years old.
bob.Introduce();     // Hi, I'm Bob and I'm 25 years old.

πŸ’‘ The this keyword

Inside a class, this refers to "the current object." It's handy when a parameter has the same name as a property:

public Person(string name, int age)
{
    this.Name = name;   // this.Name = the object's property; name = the parameter
    this.Age = age;
}

Here this.Name is the object's property and name is the constructor's parameter β€” this removes the ambiguity.

Exercise & Quiz

πŸ‹οΈ Exercise: A BankAccount Class

Objective: Design a class that bundles data and behavior, then use it.

Instructions:

  1. Create a new project called Bank.
  2. Define a BankAccount class with properties Owner (string) and Balance (decimal).
  3. Add a constructor that sets the owner and a starting balance.
  4. Add a Deposit(decimal amount) method that increases the balance, and a Withdraw(decimal amount) method that decreases it only if there are sufficient funds (otherwise print a message).
  5. Add a PrintStatement() method that displays the owner and current balance.
  6. Create an account, make a couple of deposits and withdrawals, and print the statement.

Starter Code:

BankAccount account = new BankAccount("Ada", 100m);
account.Deposit(50m);
account.Withdraw(30m);
account.Withdraw(1000m);   // should be refused
account.PrintStatement();

class BankAccount
{
    // TODO: properties Owner and Balance
    // TODO: constructor(owner, startingBalance)
    // TODO: Deposit, Withdraw, PrintStatement methods
}
πŸ’‘ Hint

Deposit is Balance += amount;. In Withdraw, check if (amount <= Balance) before subtracting; otherwise print "Insufficient funds." Use string interpolation with {Balance:C} for a currency-formatted statement.

βœ… Solution
BankAccount account = new BankAccount("Ada", 100m);
account.Deposit(50m);
account.Withdraw(30m);
account.Withdraw(1000m);   // refused
account.PrintStatement();

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

    public BankAccount(string owner, decimal startingBalance)
    {
        Owner = owner;
        Balance = startingBalance;
    }

    public void Deposit(decimal amount)
    {
        Balance += amount;
        Console.WriteLine($"Deposited {amount:C}. Balance: {Balance:C}");
    }

    public void Withdraw(decimal amount)
    {
        if (amount <= Balance)
        {
            Balance -= amount;
            Console.WriteLine($"Withdrew {amount:C}. Balance: {Balance:C}");
        }
        else
        {
            Console.WriteLine($"Insufficient funds to withdraw {amount:C}.");
        }
    }

    public void PrintStatement()
    {
        Console.WriteLine($"--- Statement for {Owner} ---");
        Console.WriteLine($"Current balance: {Balance:C}");
    }
}

Sample output:

Deposited $50.00. Balance: $150.00
Withdrew $30.00. Balance: $120.00
Insufficient funds to withdraw $1,000.00.
--- Statement for Ada ---
Current balance: $120.00

🎯 Quick Quiz

Question 1: What is the relationship between a class and an object?

Question 2: What does a constructor do?

Question 3: Two objects created from the same class…

Summary

πŸŽ‰ Key Takeaways

  • OOP bundles related data and behavior into objects.
  • A class is a blueprint; an object (instance) is a thing built from it with new. Each object has its own state.
  • Properties ({ get; set; }) hold an object's data and can validate it; methods define its behavior.
  • A constructor (same name as the class, no return type) initializes an object when it's created.
  • this refers to the current object; combining data and behavior in one class is called encapsulation.

πŸ“š Additional Resources

πŸš€ What's Next?

You've now met every core building block of C#! In the final lesson, Lesson 4.3: Putting It All Together, you'll combine variables, control flow, methods, collections, and classes into one complete program β€” a capstone that ties the whole course together.

πŸŽ‰ You think in objects now!

Classes and objects are how professional C# is written. One lesson to go β€” let's build something complete.