Featured resource
2026 Tech Forecast
2026 Tech Forecast

1,500+ tech insiders, business leaders, and Pluralsight Authors share their predictions on what’s shifting fastest and how to stay ahead.

Download the forecast
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Core Tech
Labs

Shape a Console Application with C# Syntax

Cascade Harbor Depot needs a console tool its dock staff can run each shift. Build the tool to compute storage fees, decide handling priority, process arriving crates without looping past dock capacity, parse hand-typed crate codes, track warehouse bay placement, and keep application state in validated classes instead of loose variables scattered through `Program.cs`.

Lab platform
Lab Info
Level
Beginner
Last updated
Oct 13, 2026
Duration
50m

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

    Step 1: Tour the Cascade Harbor Depot console app

    Cascade Harbor Depot

    Cascade Harbor Depot's dock staff need a console tool for each shift to log arriving crates, calculate what each one costs to store, decide how urgently each crate should be handled, and track which warehouse bay it ends up in. You'll build that tool in C#, practicing the language's specific rules for typing, operators, methods, and classes, including details that may differ from similar syntax in other languages.

    The starter project already has a src/ folder with a Program.cs entry point and several files with methods that return placeholder values. You'll complete those methods across the next four coding steps. ## The files you'll shape

    • src/FeeCalculator.cs turns a crate's weight and days stored into a fee with tiered discounts.
    • src/IntakeQueue.cs classifies crate priority and processes the arrival queue against dock capacity.
    • src/CrateBatch.cs and src/CrateCodeParser.cs refactor the fee logic into reusable, overloaded, and flexible-argument methods, and parse hand-typed input safely.
    • src/CrateTracker.cs, src/WarehouseGrid.cs, src/Crate.cs, and src/Warehouse.cs move from loose arrays into validated Crate and Warehouse classes, each living in its own file.

    Program.cs ties all of it together as the console entry point dock staff run. You won't touch every file in every step. Each step's tasks are grouped by the files where that concept applies. ## Where you're headed

    By the end of Step 5, running the console app will log a shift's worth of crates, compute each crate's discounted fee, sort crates into priority lanes, stop accepting crates once the dock queue tops out, and report which warehouse bays are occupied, all backed by classes that refuse to hold invalid data rather than trusting whatever Program.cs happens to hand them.

    Start with the piece every other feature depends on: figuring out what a crate actually costs to store.

  2. Challenge

    Step 2: Calculate crate fees with typed statements

    Typed variables and constants

    C# is statically typed: every variable's type is fixed at compile time, and the compiler enforces it long before the console app runs. A rate that never changes, like a per-kilogram storage charge, belongs in a const decimal field, not a bare literal buried in an expression. Naming it makes the fee formula in src/FeeCalculator.cs readable and keeps the rate in exactly one place if the depot ever changes its pricing.

    decimal is the type you want for money and weights here, not double, because it avoids the binary rounding surprises that creep into floating-point currency math. ## Operator precedence and grouping

    C# follows the arithmetic precedence you'd expect: multiplication before addition. But discount math is exactly where that default order goes wrong if you're not deliberate. A discount percentage has to be multiplied against the whole base fee before it's subtracted, and parentheses are how you make that explicit instead of hoping the compiler reads your intent. A small expression like baseFee - percentage * baseFee can be fine when percentage is already a decimal rate. Once percentages or extra terms enter the formula, grouping keeps the compiler's math aligned with your intent.

    With the base fee working, apply the tiered discount on top of it.

  3. Challenge

    Step 3: Route the crate intake queue with decisions and loops

    if/else decisions

    Every crate that arrives needs a handling priority, and that decision depends on more than one fact about the crate: whether it's fragile, and how much it weighs. if/else if/else chains let you check conditions in a deliberate order, which matters here. Checking fragility first means a heavy, fragile crate is still classified as urgent rather than merely standard. Order changes the outcome, not just the readability. ## switch expressions Once a crate has a priority string, turning that string into a dock lane number is a straight lookup, exactly what a switch expression is for. C#'s switch expression returns a value directly from the matched arm, and a discard pattern (_) arm catches anything that doesn't match one of your known cases. That matters when the priority string came from somewhere you don't fully trust. ## Loop termination with break and continue A dock has a hard capacity, and the truck doesn't stop unloading just because a scanner misread a weight. continue skips the rest of the current loop iteration, which is perfect for ignoring a bad reading without abandoning the whole queue. break exits the loop entirely, which is what you want the instant the dock hits capacity. Using the wrong one here either stops the shift early on one bad scan or keeps counting crates past what the dock can physically hold.

  4. Challenge

    Step 4: Refactor fee logic into methods and parse crate codes safely

    Method extraction and overloading

    Once src/CrateBatch.cs has one method that sums a batch's weight, a second scenario shows up: the same summing logic, but padded by a safety buffer percentage. Rather than writing a second, separately named method that duplicates the summing, C# lets you overload CalculateBatchWeight: declare it again with a different parameter list, and the compiler picks the right one from the call site's arguments. The two-argument overload can call the one-argument overload directly, so the summing logic only exists once. ## params for flexible arguments

    Sometimes you don't know in advance how many fee amounts you're combining: one crate, or a truckload. Use a params decimal[] parameter when you want to pass any number of decimal arguments directly, without building an array first. C# packs those arguments into an array. Inside the method, you work with that array like any other; the flexibility is at the call site. ## Safe text parsing with TryParse

    A weight typed by hand at a console prompt is just a string, and strings typed by hand are typed wrong sometimes. decimal.Parse throws on bad input, which would crash the shift's console session over one mistyped digit. decimal.TryParse instead returns a bool telling you whether parsing succeeded, with the parsed value delivered through an out parameter. That lets you handle bad input as an ordinary return value instead of an exception.

  5. Challenge

    Step 5: Track crates and bays with validated classes

    One-dimensional array traversal

    A shift's arriving crate codes live in a plain string[], and finding one means walking the array by index and comparing entries until you find a match or reach the end without one. Returning -1 for "not found" is a long-standing convention in C# arrays: it's a valid index nowhere in the array, so callers can check for it without a second flag. ## Multidimensional array traversal

    The warehouse bay layout is naturally two-dimensional: rows and columns of physical bays. C#'s bool[,] models that directly as a single rectangular array rather than an array of arrays. Traverse it with nested loops bounded by GetLength(0) and GetLength(1), rather than a single Length, since the two dimensions can differ. ## Constructors and property validation

    So far, weights and codes have been raw values passed between methods, trusted at every step. A Crate class changes that: its constructor is the one place invalid data gets rejected by throwing before an invalid object can ever exist. Once construction succeeds, every other method that receives a Crate can trust its Code and WeightKg without re-checking them. ## Splitting classes across files

    Crate and Warehouse live in their own files, src/Crate.cs and src/Warehouse.cs, because each class has one job and one reason to change. Warehouse depends on Crate because it stores crates in bays, but neither file needs to know about Program.cs. Program.cs simply constructs both classes and calls their methods. That separation lets AssignCrateToBay focus on bounds and occupancy, leaving crate validation to the Crate constructor you just wrote.

  6. Challenge

    Step 6: Run the application

    Every task is done, and each one was graded the moment you completed it. What you have not done yet is watch the whole application run at once. This is the only place the pieces you wrote separately become a single working program.

    Start the application

    Open the Terminal tab and run:

    dotnet run --project src/Lab.csproj
    

    The program runs in the terminal and prints its output there. Every behavior it shows is code you wrote in the previous steps, so read the output against what each task asked for. That is the whole lab, working as one program. ### Run the checks yourself

    The lab ran each task's test for you as you went, but they are ordinary tests and you can run them whenever you like.

    To run the whole suite:

    dotnet test tests/Lab.Tests.csproj --nologo --verbosity quiet
    

    To run one task at a time:

    bash runTest.sh Task_2_1
    

    Each failure names the task it belongs to, so the output tells you which step to go back to rather than which line to stare at. Two things worth trying before you finish: break something on purpose and watch the matching check fail, then put it back. Knowing what a failure looks like is worth as much as knowing what a pass looks like, and it costs you nothing here.

    When you are done, everything you wrote is still in the editor tabs. The lab is yours to keep reading.

About the author

Pluralsight’s AI authoring technology is designed to accelerate the creation of hands-on, technical learning experiences. Serving as a first-pass content generator, it produces structured lab drafts aligned to learning objectives defined by Pluralsight’s Curriculum team. Each lab is then enhanced by our Content team, who configure the environments, refine instructions, and conduct rigorous technical and quality reviews. The result is a collaboration between artificial intelligence and human expertise, where AI supports scale and efficiency, and Pluralsight experts ensure accuracy, relevance, and instructional quality, helping learners build practical skills with confidence.

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