Combine what you have learned: a menu-driven, error-tolerant console calculator covering Ohm's law, series/parallel resistance and grade averages.
The goal
In the last lesson of the course, we put the pieces together. We will write a small but real tool: an Engineer's Calculator that calculates according to the operation chosen from a menu and does not crash on bad input. The topics we will use: loops, the switch expression, methods, TryParse, List<T>, LINQ and error handling.
The program will have four options: (1) current calculation with Ohm's law, (2) series and parallel equivalent of two resistors, (3) grade average, (0) exit.
Step 1: Safe number reading
Instead of writing the same TryParse loop everywhere, let's write a single helper method. It keeps asking until the user enters a valid number:
static double ReadNumber(string prompt)
{
while (true)
{
Console.Write(prompt);
if (double.TryParse(Console.ReadLine(), out double value))
return value;
Console.WriteLine(" Invalid number, try again.");
}
}
Step 2: Calculation methods
Keeping the calculations separate from the user interface is a good habit: the methods only calculate, and the caller handles printing.
static double OhmCurrent(double voltage, double resistance)
{
if (resistance <= 0)
throw new ArgumentException("Resistance must be greater than zero.");
return voltage / resistance;
}
static double Series(double r1, double r2) => r1 + r2;
static double Parallel(double r1, double r2)
{
if (r1 + r2 == 0)
throw new ArgumentException("Both resistances cannot be zero at the same time.");
return r1 * r2 / (r1 + r2);
}
Parallel equivalent: for two resistors, R = R1 × R2 / (R1 + R2). For example, for 100 and 220 ohm: 22000 / 320 = 68.75 ohm.
Step 3: The whole program
Here is the combined version. You can paste it into a single Program.cs file and run it with dotnet run:
bool keepGoing = true;
while (keepGoing)
{
Console.WriteLine();
Console.WriteLine("=== ENGINEER'S CALCULATOR ===");
Console.WriteLine("1) Ohm's law (current)");
Console.WriteLine("2) Series and parallel resistance");
Console.WriteLine("3) Grade average");
Console.WriteLine("0) Exit");
Console.Write("Your choice: ");
string? choice = Console.ReadLine();
try
{
switch (choice)
{
case "1":
double v = ReadNumber("Voltage (V): ");
double r = ReadNumber("Resistance (ohm): ");
double i = OhmCurrent(v, r);
Console.WriteLine($"Current: {i:F4} A, power: {v * i:F3} W");
break;
case "2":
double r1 = ReadNumber("1st resistance (ohm): ");
double r2 = ReadNumber("2nd resistance (ohm): ");
Console.WriteLine($"Series: {Series(r1, r2):F2} ohm");
Console.WriteLine($"Parallel: {Parallel(r1, r2):F2} ohm");
break;
case "3":
GradeAverage();
break;
case "0":
keepGoing = false;
Console.WriteLine("See you!");
break;
default:
Console.WriteLine("Please choose a number from the menu.");
break;
}
}
catch (ArgumentException ex)
{
Console.WriteLine($"Could not calculate: {ex.Message}");
}
}
static void GradeAverage()
{
var grades = new List<double>();
Console.WriteLine("Enter the grades one by one (press Enter on an empty line to finish):");
while (true)
{
Console.Write($" Grade {grades.Count + 1}: ");
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) break;
if (double.TryParse(input, out double grade) && grade >= 0 && grade <= 100)
grades.Add(grade);
else
Console.WriteLine(" You must enter a number between 0 and 100.");
}
if (!grades.Any())
{
Console.WriteLine("No grades were entered.");
return;
}
Console.WriteLine($"Average: {grades.Average():F2}");
Console.WriteLine($"Highest: {grades.Max()} Lowest: {grades.Min()}");
Console.WriteLine($"Number of passing grades (>= 60): {grades.Count(n => n >= 60)}");
}
static double ReadNumber(string prompt)
{
while (true)
{
Console.Write(prompt);
if (double.TryParse(Console.ReadLine(), out double value))
return value;
Console.WriteLine(" Invalid number, try again.");
}
}
static double OhmCurrent(double voltage, double resistance)
{
if (resistance <= 0)
throw new ArgumentException("Resistance must be greater than zero.");
return voltage / resistance;
}
static double Series(double r1, double r2) => r1 + r2;
static double Parallel(double r1, double r2)
{
if (r1 + r2 == 0)
throw new ArgumentException("Both resistances cannot be zero at the same time.");
return r1 * r2 / (r1 + r2);
}
A sample run (on a machine with English settings, the decimal separator is a period):
=== ENGINEER'S CALCULATOR ===
1) Ohm's law (current)
2) Series and parallel resistance
3) Grade average
0) Exit
Your choice: 2
1st resistance (ohm): 100
2nd resistance (ohm): 220
Series: 320.00 ohm
Parallel: 68.75 ohm
What did we learn? We split the program into small methods; we validated the input in one place; we threw errors and caught them at a single point; we managed the menu loop with a bool flag. Real software grows this way.
Try it yourself
- Add a new operation: 4) Voltage divider (
Vout = Vin × R2 / (R1 + R2)). - Make repeating easier: Save the last calculated result into a
List<string>history and list it with a "5) History" option. - Move it into a class: Put the calculation methods inside a
static class Calculationsand separate them from the user interface. - Write to a file: On exit, save the history to a text file with
File.WriteAllLines.
You have finished this course; you now have the foundation to write real tools in C#. The next stops: file operations, async/await, windowed applications with WinForms, and the web with ASP.NET.
// Mini quiz
Click an option; you will see right away, with the reason, whether it is correct or not.
Mark it when you finish: your progress is saved and you earn +20 XP.
// Final exam and certificate
20 random questions from the lessons, 30 minutes, pass mark 70%. If you pass, you get a verifiable certificate of achievement (with a QR code).
Take the final examTip: ← → keys let you move between lessons.