Aim
To build a ten-question quiz that is scored against a time limit, using named value tuples for the question bank and System.Diagnostics.Stopwatch for high-resolution timing.
Theory
Three advanced constructs meet in this practical. (1) ValueTuple arrays: (string q, int ans)[] declares an array of value tuples with NAMED elements — questions[i].q and questions[i].ans are compiler-tracked aliases for Item1/Item2 (the names live only in metadata via the TupleElementNames attribute). Tuples are structs, so ten questions occupy one contiguous array allocation rather than ten separate heap objects, and question text can never drift out of sync with its answer key — the classic parallel-array bug is structurally impossible. (2) Stopwatch vs DateTime: Stopwatch wraps the operating system's high-resolution performance counter (QueryPerformanceCounter on Windows) with sub-microsecond granularity and is monotonic — immune to NTP corrections, daylight-saving jumps and manual clock changes that make DateTime.Now subtraction unreliable; Stopwatch.StartNew() constructs and starts it in a single call. (3) TimeSpan comparison: sw.Elapsed <= TimeSpan.FromSeconds(30) compares two TimeSpan structs through their overloaded relational operator, expressing the time budget declaratively. Finally, the program replaces interactive Console.ReadLine input with a scripted demoAnswers array so it runs deterministically in a non-interactive online runner — the same substitution technique (replacing an interactive dependency with a scripted fake) that unit tests use every day.
Requirements
- .NET SDK 8.0+ or the RUN CODE button; the
System.Diagnosticsnamespace suppliesStopwatch.
Procedure
- Create the project:
dotnet new console -n TimerQuiz,cd TimerQuiz, paste the code. - Run
dotnet run; confirm the score is 10/10 and the elapsed time prints with two decimals. - Sabotage one entry of
demoAnswers(change 15 to 14) and re-run → score 9/10, proving the grader actually compares answers. - For an interactive version, replace the scripted answer with
int.TryParse(Console.ReadLine(), out int answer)inside the loop.
Explanation of the Code
var questions = new (string q, int ans)[] { ("2 + 2 = ? (4)", 4), ... };— a collection initialiser of named tuples keeps each question and its key physically together.Stopwatch sw = Stopwatch.StartNew();starts timing immediately before the loop — the placement defines precisely what is measured.- The
forloop printsQ{i + 1}, pulls the scripteddemoAnswers[i], and incrementsscorewhen it equalsquestions[i].ans— field access by tuple element name. sw.Stop();freezes the counter;bool withinTime = sw.Elapsed <= TimeSpan.FromSeconds(30);evaluates the 30-second budget as a single boolean.- The interpolation hole
{sw.Elapsed.TotalSeconds:F2}uses a format specifier — fixed-point notation with exactly two decimal places.
Expected Output
Q1: 2 + 2 = ? (4)
Answer used: 4
Q2: 5 x 3 = ? (15)
Answer used: 15
...continues through Q10...
Score: 10/10
Time Taken: 0.01 sec
Within timer limit.
(The exact seconds vary per machine; any value at or under 30 prints "Within timer limit.")
🎯 Viva Questions
- Why Stopwatch instead of subtracting
DateTime.Nowvalues? — It is a monotonic high-resolution counter; wall-clock time can jump (NTP/DST) and ticks at only ~15 ms granularity. - What is a ValueTuple? — A struct with public fields and optional compiler-tracked element names;
(string q, int ans)isValueTuple<string, int>. - Where are tuple element names stored? — Only in compiler metadata; at run time the fields are
Item1andItem2. - What does
:F2mean inside interpolation? — Fixed-point formatting with exactly two decimal places. - Why script the answers instead of reading input? — Determinism in non-interactive runners — the same idea as faking a dependency in unit tests.
- Difference between
sw.Elapsedandsw.ElapsedMilliseconds? — ATimeSpanstruct versus alongcount of whole milliseconds.