Module 1 · First Steps · Lesson 2 of 37
Values, Expressions and Reliable Input
What this lesson assumes
You can create and run the console project from Lesson 1. Keep net10.0, implicit usings, and nullable checking enabled. This lesson introduces a variable, a named place to hold a value, and a type, which describes the values and operations permitted for it.
By the end, you will be able to:
- Choose
int,bool, orstringfor simple StudyDeck data and trace assignments. - Predict integer arithmetic, comparisons, and combined conditions.
- Distinguish text that can be parsed from a number that satisfies the product's rules.
StudyDeck tasks will eventually have an integer identifier, a title, a planned duration from 1 through 240 minutes, and a completion flag. Today we keep those ideas in individual variables. There is no collection of tasks yet. See the analogy section for the distinction between a value's type and its permitted business range.
Values have meaning and a type
Consider this fragment:
int id = 1; string title = "Read one chapter"; int minutes = 45; bool completed = false;
Each declaration introduces a name and an initial value. int holds whole numbers within a finite range. bool holds true or false. string represents text. The equals sign assigns a value; it does not assert a mathematical identity that remains true forever.
After int remaining = minutes;, changing minutes to 60 does not also change remaining. The integer value was copied. Likewise, int does not prevent assigning -5: that is a representable integer even though it is an invalid StudyDeck duration. Types eliminate some mistakes; application validation handles additional rules. Microsoft: value types
A declaration can use var, as in var minutes = 45;. The compiler infers int from the initializer; the variable does not become a container that can later accept any type. Prefer an explicit type while learning if it makes the data meaning clearer.
Expressions are evaluated before assignment
An expression computes a value. In minutes = minutes + 5;, the old value is read, five is added, and the result becomes the new value. minutes += 5; is a convenient equivalent for this simple integer variable.
Operator choice matters:
int total = 95; Console.WriteLine(total / 60); Console.WriteLine(total % 60); Console.WriteLine(2 + 3 * 4); Console.WriteLine((2 + 3) * 4);
Output:
1 35 14 20
Integer division gives an integer quotient, truncating toward zero. The remainder operator % provides the amount left after division. Multiplication has higher precedence than addition; parentheses can make the intended grouping explicit. These calculations make 95 minutes into one whole hour and 35 remaining minutes. Microsoft: arithmetic operators
Assigning 5 / 2 to a double afterward does not restore the discarded fraction: the integer division already produced 2. If a fractional result is needed, choose a suitable numeric operand before division. double and decimal have different representations and uses; neither makes every possible fraction exact. Our duration model deliberately uses whole minutes, so no floating-point calculation is required.
Example 1: a complete input-checking experiment
Parsing converts a textual representation into a typed value. TryParse reports success as a Boolean and supplies the parsed integer through an out argument. Here out int minutes declares the variable in which the operation places its result. Lesson 4 will explain parameters more fully.
This complete program uses fixed input strings so its output is reproducible:
string rawMinutes = "45";
bool parsed = int.TryParse(rawMinutes, out int minutes);
bool inRange = parsed && minutes >= 1 && minutes <= 240;
Console.WriteLine($"Parsed: {parsed}");
Console.WriteLine($"Minutes: {minutes}");
Console.WriteLine($"In range: {inRange}");
Console.WriteLine($"Whole hours: {minutes / 60}");
Console.WriteLine($"Remaining minutes: {minutes % 60}");
bool badParsed = int.TryParse("forty-five", out int badMinutes);
Console.WriteLine($"Bad parsed: {badParsed}");
Console.WriteLine($"Bad result: {badMinutes}");Output:
Parsed: True Minutes: 45 In range: True Whole hours: 0 Remaining minutes: 45 Bad parsed: False Bad result: 0
The dollar sign introduces an interpolated string. Expressions inside braces supply values in the displayed text. A Boolean is displayed as True or False here, even though its C# literals are spelled true and false.
For the string overload used here, int.TryParse returns false when the text cannot represent an accepted integer, including a value outside the int range. Its output result is zero on failure. Always use the success flag; zero is also a valid parsed integer for the text "0". Microsoft: Int32.TryParse
Parsing is only the first gate
The comparisons >= and <= produce Boolean values. && means both conditions must hold; it evaluates its right operand only if the left operand is true. This is short-circuit evaluation. With the chain above, valid input must parse and satisfy both bounds. || means at least one condition is true; ! reverses a Boolean value. Microsoft: Boolean operators
Try changing the input to "0", then "241". Both parse, but inRange becomes false. This is the counterexample to “TryParse means the value is valid for my application.” Conversely, "45" passes both checks.
Do not replace minutes >= 1 && minutes <= 240 with an OR. For example, 500 satisfies the first comparison and would be accepted by that incorrect condition. Write down a below-range, inside-range, and above-range value when reviewing a boundary.
The overload in this lesson uses the current culture's integer parsing conventions. The fixed plain digit inputs shown do not require a decimal separator. Real applications should define any culture or accepted-format requirements instead of assuming all users type numbers identically.
Example 2: connect the boundary to the console
This independent fragment reads one line and reports whether integer parsing succeeded:
Console.WriteLine("Enter whole minutes:");
Console.WriteLine(int.TryParse(Console.ReadLine(), out int entered));
Console.WriteLine(entered);If the entered line is 25, the program prints the prompt, then True, then 25. If the entered line is abc, it prints the prompt, then False, then 0. The user's typed line may also be echoed by the terminal; it is not another WriteLine call.
Console.ReadLine() obtains text and can return no text at the end of input. TryParse handles that missing input by returning false. This fragment has not yet enforced the 1–240 range and must not be mistaken for complete validation.
Exercises with solutions
1. Trace a copied value. Predict int minutes = 20; int original = minutes; minutes += 10; followed by printing original and minutes.
Solution: The lines are 20 and 30. The assignment copied the integer value; it did not create a formula that keeps original synchronized.
2. Validate the upper boundary. For inputs "240", "241", and "two", state parsed and inRange.
Solution: They are True/True, True/False, and False/False. The last result must not be accepted merely because the failure output is zero; use both the parse result and the range condition.
Interview questions with reasoning
Is var dynamically typed? No. It asks the compiler to infer a static type from the initializer. var count = 3; is still an integer variable.
Why use TryParse for ordinary user mistakes? It provides an explicit success result for text conversion, letting the program make a normal decision. It still does not validate product-specific limits.
Why does a decimal destination not fix integer division? Operands determine the division operation first. Assignment receives the result after that operation, so lost fractional information cannot be recovered by widening the destination.
Analogy
A labelled form and two separate checks
Imagine a StudyDeck paper form with a box labelled “whole minutes.” The type is like the shape of the box: it tells the processing system what kind of value it expects. A completion box accepts yes or no, while a title box accepts text. Putting a title into the minutes box is a kind mismatch.
Now imagine two clerks. The first asks, “Can I read this as a whole number?” The text 241 passes that check. The second asks, “Does our study-session policy allow that number?” With the limit of 240, the second clerk rejects it. TryParse is the first check; the range condition is the second.
Copying a written number onto another form resembles assigning one integer variable to another. Changing the first form afterward does not erase and rewrite the copy.
The analogy breaks because C# types are enforced by precise language and runtime rules, not by a person's interpretation of handwriting. Also, a variable is not a physical box with unlimited room: an int has a finite numeric range. Neither the label nor a successful conversion decides every rule of your application.
Quick reference
Values and input checks
int: whole-number data;bool: true/false;string: text.=assigns.==compares. Assigning an integer copies its value.var minutes = 45;infers int; it does not remove static typing.95 / 60is 1;95 % 60is 35.- Multiplication precedes addition; use parentheses to express intended grouping.
int.TryParse(text, out int minutes)reports conversion success separately from its output value.- For StudyDeck:
parsed && minutes >= 1 && minutes <= 240. &&requires both sides and short-circuits;||requires either;!reverses a Boolean.$"Minutes: {minutes}"inserts a value into text.
Parsing success is not business validation. Test 0, 1, 240, 241, nonnumeric text, and missing input. Choose an explicit format or culture policy when an application needs one.