Featured resource
2025 Tech Upskilling Playbook
Tech Upskilling Playbook

Build future-ready tech teams and hit key business milestones with seven proven plays from industry leaders.

Check it out
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
Labs

Guided: C# 14 Object-oriented Modeling

Object-oriented design is a foundational skill for building maintainable and scalable software. In this Guided Code Lab, you will model a real-world vehicle fleet management system using modern C# 14 features and object-oriented principles. You will practice designing base classes, extending behavior through inheritance, enforcing contracts with interfaces, and managing objects using polymorphism. By the end of this lab, you will be confident in translating domain requirements into clean, extensible C# models.

Lab platform
Lab Info
Last updated
Mar 04, 2026
Duration
45m

Contact sales

By clicking submit, you agree to our Privacy Policy and Terms of Use, and consent to receive marketing emails from Pluralsight.
Table of Contents
  1. Challenge

    Introduction

    In this lab, you will model a real-world system using object-oriented principles in C#.

    As a developer, your responsibility is not just to write code that works. Your responsibility is to design models that:

    • Represent the domain correctly
    • Support future extensibility
    • Encourage clean structure
    • Demonstrate proper use of object-oriented principles

    This lab focuses on making thoughtful modeling decisions.


    Lab Scenario

    You are working for a logistics company that manages a fleet of vehicles.

    The company owns different types of vehicles and needs a clean, scalable way to manage them in code. Your task is to design a Vehicle Fleet Management System that models this domain accurately.

    The company owns:

    • Cars
    • Trucks

    Each vehicle has common properties such as:

    • Registration number
    • Manufacturer
    • Year

    However, there are important differences:

    • Cars and trucks behave differently when they start
    • Trucks require specialized maintenance
    • The company also has office equipment that requires maintenance but is not a vehicle

    Your goal is to design a clean object model that supports:

    • Shared vehicle behavior
    • Specialized vehicle behavior
    • Maintenance functionality across different asset types

    You will focus entirely on object-oriented modeling.


    Learning Objectives

    Now that you understand the lab scenario, you will begin translating the requirements into an object-oriented design.

    In this lab, you will go through the below points:

    • Model shared behavior using a base class
    • Specialize behavior using inheritance
    • Define a contract using an interface
    • Implement polymorphism using both inheritance and interfaces
    • Understand when to use inheritance and when to use interfaces

    By the end of this lab, you will clearly understand the difference between modeling identity using inheritance and modeling capability using interfaces. >Each step contains tasks clearly marked with comments like // Task 2.1

    info> If you get stuck on a task, you can view the solution in the solution folder in your Filetree, or click the Task Solution link at the bottom of each task after you've attempted it.

  2. Challenge

    Examine the Project Structure and Identify Shared Behavior

    Before modifying any code, you will first understand the structure of the project and analyze the domain from a modeling perspective.

    In professional development, you rarely start from scratch. Most of the time, you inherit an existing codebase. Your first responsibility is to understand what already exists before making changes.


    Review the Project Structure

    Observe the folder structure:

    
    FleetManagement/
    │
    ├── Program.cs
    │
    ├── Models/
    │   ├── Vehicle.cs
    │   ├── Car.cs
    │   ├── Truck.cs
    │   └── OfficeAsset.cs
    │
    └── Interfaces/
        └── IMaintainable.cs
    
    

    Program.cs

    This is the entry point of the application.

    It already contains basic code that:

    • Creates instances of Car and Truck
    • Stores them in collections
    • Calls methods such as Start() and DisplayInfo()

    Models Folder

    The Models folder contains the core domain entities:

    • Vehicle
    • Car
    • Truck
    • OfficeAsset

    These classes represent real-world business concepts, keeping domain models separate from application logic.


    Interfaces Folder

    The Interfaces folder contains contracts that classes may implement.

    You will modify and apply IMaintainable later in the lab.

    For now, simply note that the system has been structured to separate:

    • Identity (Models)
    • Capability contracts (Interfaces)

    Run the Application

    Before making any changes, run the application to observe its current behavior.

    You can run the application in either of the following ways:

    • Click the Run button located at the bottom right of the Terminal.

    • Navigate to the /FleetManagement directory, then run dotnet run in the terminal.

    info>You will use either of these options throughout the lab whenever you need to run the program.


    Output:

    Fleet Management System
    
    Vehicle is starting...
    Reg: CAR123, Manufacturer: Toyota, Year: 2022
    
    Vehicle is starting...
    Reg: TRK789, Manufacturer: Volvo, Year: 2020
    

    Analyze the Base Class

    Open Models/Vehicle.cs. Review the class. Notice that it contains:

    • Common properties: RegistrationNumber, Manufacturer, Year
    • A constructor
    • A Start() method
    • A DisplayInfo() method

    Now think about the domain.

    The company owns cars and trucks. What do they share?

    • Registration number
    • Manufacturer
    • Year
    • The ability to start
    • The ability to display information

    These shared characteristics justify the Vehicle base class.

    info> Inheritance models an "is-a" relationship.

    A Car is a Vehicle.
    A Truck is a Vehicle.


    Identify What Needs Improvement

    Look at the Start() method.

    Does it allow specialization?

    Currently, every vehicle starts the same way. But in reality:

    • A car might start smoothly
    • A truck might start loudly after safety checks
    • An electric vehicle might start silently

    Your design should support this flexibility.

    In the next step, you will enable specialization in the base class.

  3. Challenge

    Enable Specialization in Base Class

    In the previous step, you reviewed the project structure and analyzed the Vehicle class.

    Although all vehicles share the ability to start, the way they start may differ. Your current design does not support this flexibility.


    The Design Limitation

    Open Models/Vehicle.cs and locate the Start() method.

    public void Start()
    {
        Console.WriteLine("Vehicle is starting...");
    }
    

    Next, you will modify the base class to properly support specialization.


    Understanding the virtual Keyword

    In C#, if you want a derived class to override a method defined in a base class, that method must be marked as virtual.

    public virtual void Start()
    

    The virtual keyword tells the runtime:

    info> "This method may be overridden in a derived class." ---

    Run the Application

    You will not notice any difference yet.

    That is expected.

    You have enabled specialization, but you have not implemented it yet.

    In the next step, you will override this behavior in Car and Truck and observe polymorphism in action.

  4. Challenge

    Apply Inheritance and Override Behavior

    In the previous step, you marked the Start() method in the Vehicle class as virtual.

    Now you will override this method in both Car and Truck so that each vehicle type behaves differently when starting.

    This demonstrates inheritance-based polymorphism. Now that you have overridden the Start() method in Car, apply the same approach to the Truck class. >Run the Application

    Observe the output.

    Fleet Management System
    
    Car engine is starting smoothly...
    Reg: CAR123, Manufacturer: Toyota, Year: 2022
    
    Truck is performing safety checks and starting loudly...
    Reg: TRK789, Manufacturer: Volvo, Year: 2020
    

    Even though both Car and Truck are stored as Vehicle types in Program.cs, the correct overridden method is executed at runtime.

    info> Executing the overridden method based on the actual object type is called Runtime Polymorphism.

    In the next step, you will extend this specialization further by adding type-specific properties.

  5. Challenge

    Extend the Model with Type-Specific Properties

    So far, you have specialized behavior by overriding the Start() method.

    Now, you will extend the model further by overriding another method and reusing the base implementation.

    Inheritance allows derived classes to:

    • Reuse shared properties and behavior from the base class
    • Extend existing behavior
    • Override base methods when necessary

    In this step, you will override the DisplayInfo() method and use the base keyword to extend the existing implementation.


    The DisplayInfo() method in the Vehicle class prints common information such as:

    • Registration number
    • Manufacturer
    • Year

    Rather than replacing this behavior entirely, you will reuse it and add a vehicle-specific message.

    This demonstrates how derived classes can extend base functionality without duplicating code. Well done! The Car class now extends the base display behavior. Now repeat the same for Truck. >Run the application:

    Fleet Management System
    
    Car engine is starting smoothly...
    Reg: CAR123, Manufacturer: Toyota, Year: 2022
    Doors: 4
    
    Truck is performing safety checks and starting loudly...
    Reg: TRK789, Manufacturer: Volvo, Year: 2020
    Load Capacity: 18.5 tons
    

    Observe the output.

    You should now see:

    • Shared vehicle information
    • Car-specific information
    • Truck-specific information

    This demonstrates how derived classes can:

    • Extend state
    • Extend behavior
    • Reuse shared implementation

    In the next step, you will introduce an interface to model shared capability across different types.

  6. Challenge

    Introduce a Behavioral Contract Using an Interface

    So far, you have modeled identity using inheritance.

    Inheritance works well when there is an "is-a" relationship.

    Now consider a new requirement. The logistics company also owns office equipment that requires maintenance.

    Examples:

    • Generators
    • Printers
    • Servers

    These are not vehicles. However, they still require maintenance.

    This introduces a new modeling question:

    Should office equipment inherit from Vehicle? The answer is No.

    Office equipment is not a vehicle. Instead of modeling identity, you now need to model capability.

    The capability is:

    • Being maintainable.

    This is where interfaces are appropriate.

    info> An interface defines a contract that classes agree to follow.

    Now you will define a contract in IMaintainable.cs that represents maintenance behavior.


    If you run the application now, you will notice that nothing has changed. That is expected.

    Defining an interface does not affect program behavior until it is implemented by a class.

    info> An interface defines a contract, but it does not provide implementation.

    In the next step, you will implement IMaintainable in Vehicle and define a default maintenance behavior inherited by derived classes.

  7. Challenge

    Implement the Interface in the Vehicle Hierarchy

    In the previous step, you defined the IMaintainable interface.

    However, defining an interface alone does not change behavior.

    Now you will apply this contract to the vehicle hierarchy. Any class that implements IMaintainable must provide an implementation of PerformMaintenance(). By implementing the interface in the base class:

    • All derived classes automatically become maintainable.
    • Car and Truck inherit this maintenance behavior.
    • You maintain a clean hierarchy. You have added capability to the model.

    In the next step, you will override maintenance behavior in Truck and implement the interface in OfficeAsset to demonstrate interface-based polymorphism.

  8. Challenge

    Override and Apply the Maintenance Contract Across Different Types

    In the previous step, you implemented IMaintainable in the Vehicle class. Because Car and Truck inherit from Vehicle, they automatically gained maintenance capability.

    Now you will:

    • Override maintenance behavior in Truck
    • Implement the same interface in a class that does not inherit from Vehicle
    • Use a collection of IMaintainable to demonstrate interface-based polymorphism Notice that the class OfficeAsset does not inherit from Vehicle. Now that OfficeAsset implements IMaintainable, you can treat it the same way as vehicles when performing maintenance. >Run the Application
    Fleet Management System
    
    Car engine is starting smoothly...
    Reg: CAR123, Manufacturer: Toyota, Year: 2022
    Doors: 4
    
    Truck is performing safety checks and starting loudly...
    Reg: TRK789, Manufacturer: Volvo, Year: 2020
    Load Capacity: 18.5 tons
    
    Maintenance Operations:
    
    Performing general maintenance...
    Inspecting heavy-duty components of truck TRK222
    Servicing office asset: Main Office Generator
    

    Observe the final behavior.

    You have now seen two forms of polymorphism:

    1. Inheritance-based polymorphism using List<Vehicle>
    2. Interface-based polymorphism using List<IMaintainable>

    info>Inheritance models identity.
    Interfaces model capability.

  9. Challenge

    Conclusion and Next Steps

    Congratulations! You have successfully completed the lab.

    At this point, you have modeled a real-world system using inheritance and interfaces in C#.

    You:

    • Created a base class to represent shared identity
    • Specialized behavior using method overriding
    • Defined a contract using an interface
    • Demonstrated both inheritance-based and interface-based polymorphism

    You now understand that:

    • Inheritance models what an object is
    • Interfaces model what an object can do

    Next Steps

    You can extend this system by:

    • Adding new vehicle types
    • Creating additional interfaces
    • Exploring composition as an alternative to inheritance

    You have built a clean, extensible foundation.

    Well done!

About the author

Amar Sonwani is a software architect with more than twelve years of experience. He has worked extensively in the financial industry and has expertise in building scalable applications.

Real skill practice before real-world application

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Learn by doing

Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.

Follow your guide

All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.

Turn time into mastery

On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.

Get started with Pluralsight