C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
18: Practice Exercise: Building a Simple Calculator
When you first start building something like a calculator, it's tempting to focus entirely on the math. You'll likely think, "I know how to add and subtract, the hard part is just getting the numbers." This leads to a very common trap I see early on: the belief that double.Parse() is the correct way to handle user input.
The trap of assuming double.Parse is "safe enough"
Most tutorials show you double.Parse(Console.ReadLine()) because it's short. It works perfectly as long as the user is a robot. But in the real world, users are chaotic. If you use Parse and a user accidentally types "12.a" or just hits enter without typing anything, your program doesn't just "fail"—it throws a FormatException and crashes instantly. I've seen plenty of junior devs spend hours debugging their calculation logic, only to realize the app was crashing before it even reached the math.
// This is the "dangerous" way
Console.WriteLine("Enter a number:");
double num = double.Parse(Console.ReadLine()); // Crash city if the input is "abc"
Using TryParse to build a crash-proof interface
If you want your code to feel professional, you have to stop trusting the user. The correct approach in C# is double.TryParse(). Instead of throwing an exception when it fails, it returns a boolean (true or false) and uses an out parameter to hand you the converted value if it succeeded. It's a bit more verbose, but it's the difference between a tool that works and a tool that breaks.
Console.WriteLine("Enter a number:");
if (double.TryParse(Console.ReadLine(), out double result))
{
// 'result' now holds the parsed number
Console.WriteLine($"You entered: {result}");
}
else
{
Console.WriteLine("That's not a valid number. Please try again.");
}
The Loop-and-Switch pattern for a usable tool
A calculator that runs once and then closes is a script, not a program. To make this a real utility, you'll want to wrap your logic in a while loop. Inside that loop, you can use a switch expression to map the user's operator choice (like '+', '-', '*', '/') to the actual math operation.
I personally prefer switch expressions over long if/else if chains here. They are cleaner, more readable, and they force you to think about the "default" case—what happens when the user types a '?' instead of a '+'?
string operation = Console.ReadLine();
double calculatedValue = operation switch
{
"+" => num1 + num2,
"-" => num1 - num2,
"*" => num1 * num2,
"/" => num2 != 0 ? num1 / num2 : 0, // Quick check to avoid division by zero
_ => 0 // The default case
};
Notice that little ternary operator I tucked into the division line? Division by zero is the classic "calculator killer." Even with double (which would result in Infinity), it's better to handle that logic explicitly so your output makes sense to a human.
📋 Practical Task
Build the Robust Four-Function Command-Line Calculator
Your task is to create a fully functional calculator that doesn't crash when given bad input. Your program should implement the following requirements:
- The Infinite Loop: The calculator should continue asking for calculations until the user types 'exit' as their operator.
- Input Validation: Use
double.TryParsefor both number inputs. If the user enters something invalid, print an error message and ask for that specific number again (do not let the program crash). - Operation Handling: Use a
switchexpression to handle addition, subtraction, multiplication, and division. - The Zero Guard: Specifically handle division by zero. Instead of allowing the result to be
Infinity, print a friendly message saying "Cannot divide by zero" and skip to the next calculation. - Clean Output: Display the final result clearly (e.g., "10 + 5 = 15") before looping back to the start.
There are no comments for now.