Checkpoint: C# Basics
You've learned data types, casting, Console input, strings, List , Dictionary , properties and enums — let's combine them. This checkpoint isn't new theory; it's where the pieces click together into real, working programs. You'll warm up, recap what you know, build a complete program from scratch, and test yourself with a short quiz.
Learn Checkpoint: C# Basics in our free C# course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.
Part of the free C# course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You've Learned
Everything in this checkpoint draws on the eight lessons you just completed. Here's the toolkit you now carry into every C# program:
Topic
You can now…
Key tool
Data Types
Pick the right type for any value
int, double, decimal, bool
Type Casting
Convert and validate safely
TryParse, (int)
User Input
Read and re-prompt for input
Console.ReadLine
Strings
Format, split, join, build text
$"...", StringBuilder
List<T>
Store ordered, growable data
Add, RemoveAll, Sort
Dictionary
Look up and tally by key
TryGetValue, GetValueOrDefault
Properties
Wrap data with validation
{ get; set; }
Enums
Model fixed sets of options
enum, switch
1. Warm-Up
Before the main challenge, run this short program that already weaves together five skills: splitting strings, parsing with TryParse , collecting into a List<int> , sorting, and interpolated output. Trace each line and predict the result before you run it.
2. Build Challenge: Word Frequency Report
Now the main event. Build a complete word frequency report : split a sentence into words, tally each word in a Dictionary , print every word with its count, and announce the most frequent word. This is a genuine real-world task — search engines, analytics, and spam filters all start here. Attempt it yourself in the editor before revealing the solution.
🎯 Multi-Step Build Challenge
The starter below has the brief, the expected output, and a scaffold in comments. Combine strings + Dictionary + loops + interpolation to make it work.
Here's one clean way to do it. Compare it with your attempt — notice how the count and the "best so far" are tracked in the same loop, so we never scan the dictionary twice.
🔎 Stretch: model real data
Want to push further? This example brings together a class with properties , an enum , a computed property , and a List<Task> — exactly how a real task list app stores its data. Read it, run it, then try adding a new task or a fourth Priority level.
⏱ Timed Quiz
📝 Checkpoint Quiz
Answer each in your head (or out loud) before revealing. Six questions covering the whole basics track.
Q1. Which type should hold a price like 19.99 that must be exact?
decimal (written 19.99m ). double has binary rounding drift and is wrong for money.
Q2. The user types "abc" . What does int.TryParse("abc", out int n) return, and what is n ?
It returns false , and n is set to its default of 0 . No exception is thrown — that's why TryParse is safe for input.
Q3. You read a key that isn't in a Dictionary with the indexer. What happens, and what should you use instead?
The indexer throws KeyNotFoundException . Use TryGetValue (or GetValueOrDefault / ContainsKey ) to read safely.
Q4. Why can't you safely remove items from a List inside a foreach over that same list?
Changing the collection mid-iteration throws InvalidOperationException . Use RemoveAll(predicate) , or loop backwards with a for loop using indexes.
Q5. What's the advantage of an auto-property over a public field?
A property keeps a stable public surface: you can later add validation in the setter, make the setter private, or compute the value — all without breaking calling code. A public field locks you out of that.
Q6. Given enum Level { Low = 1, Medium, High } , what is (int)Level.High ?
3 — Low is explicitly 1, so Medium auto-increments to 2 and High to 3.
Pro Tips for the Road Ahead
- 💡 Reach for the right collection: List for ordered data, Dictionary for lookups by key.
- 💡 Validate at the boundary: parse and check input the moment it arrives, before it spreads through your code.
- 💡 Let types do the work: enums and properties catch whole classes of bugs at compile time.
- 💡 Read your output: if a program runs but prints the wrong thing, the bug is usually a type or a loop boundary — exactly what you practised here.
Watch-Outs You've Now Met
- Integer division: 7 / 2 is 3 . Cast to double for a real average.
- Concatenating input: "5" + 3 is "53" — parse before doing maths.
- Missing keys / out-of-range indexes: guard with TryGetValue and Count checks.
- Forgetting using s: List / Dictionary need System.Collections.Generic ; Sum / Average need System.Linq .
Frequently Asked Questions
🎉 Checkpoint Complete
- ✅ You combined input, parsing, collections, strings and formatting into one working program
- ✅ You built a real word-frequency report with the Dictionary tally pattern
- ✅ You modelled data with classes, properties and enums in a single list
- ✅ You passed the quiz on the core gotchas: division, concatenation, missing keys, mutation
- ✅ Next up: Nullable Types & Null Operators — handle "no value" safely and elegantly
Practice quiz
Which C# type should hold a price like 19.99 that must stay exact?
- double
- float
- decimal
- int
Answer: decimal. decimal (written 19.99m) avoids the binary rounding drift that makes double wrong for money.
The user enters "abc". What does int.TryParse("abc", out int n) return, and what is n?
- Returns true, n is 0
- Returns false, n is 0
- Throws a FormatException
- Returns false, n is -1
Answer: Returns false, n is 0. TryParse returns false on bad input and sets n to its default of 0, without throwing.
Reading a key that is NOT in a Dictionary using the indexer (dict[key]) does what?
- Returns null
- Returns 0
- Throws KeyNotFoundException
- Adds the key automatically
Answer: Throws KeyNotFoundException. The indexer throws KeyNotFoundException for a missing key; use TryGetValue or GetValueOrDefault to read safely.
What is the one-line idiom to tally counts in a Dictionary<string,int> called 'counts'?
- counts.Add(word, 1)
GetValueOrDefault returns 0 for a missing word, so adding 1 starts a new tally or grows an existing one.
Why can't you safely remove items from a List inside a foreach over that same list?
- foreach is read-only by design
- Modifying the collection mid-iteration throws InvalidOperationException
- It silently skips elements
- Lists cannot be removed from at all
Answer: Modifying the collection mid-iteration throws InvalidOperationException. Mutating a collection during foreach throws InvalidOperationException; use RemoveAll or a reverse for loop.
Which method reads a line of text typed by the user at the console?
- Console.Write
- Console.ReadKey
- Console.ReadLine
- Console.Input
Answer: Console.ReadLine. Console.ReadLine returns the full line the user typed as a string (or null at end of input).
What does string interpolation with $"Hello {name}" do?
- Prints a literal {name}
- Inserts the value of the name variable into the string
- Throws if name is null
- Only works with numbers
Answer: Inserts the value of the name variable into the string. An interpolated string ($"...") substitutes the value of each {expression} into the text.
What is the advantage of an auto-property over a public field?
- It runs faster
- It lets you later add validation or change access without breaking callers
- It uses less memory
- Fields cannot be public
Answer: It lets you later add validation or change access without breaking callers. A property keeps a stable public surface, so you can add a setter check or make it computed later.
Given enum Level { Low = 1, Medium, High }, what is (int)Level.High?
- 1
- 2
- 3
- 0
Answer: 3. Low is explicitly 1, so Medium auto-increments to 2 and High to 3.
Integer division: what does the C# expression 7 / 2 evaluate to?
- 3.5
- 3
- 4
- 3.0
Answer: 3. Two ints divide as integers, discarding the remainder; cast to double for 3.5.
Continue this course
- Previous: Enums
- Next: Nullable Types & Null Operators