A program becomes much more interesting when it responds to the person using it. Console programs talk to users through the terminal: they print a prompt, read what the user types, and print a result. Many real tools work this way, from dotnet and git to small scripts that automate work.
In C#, Console.WriteLine and Console.Write handle output, and Console.ReadLine reads a whole line of input as a string. The tricky part is that users don't always type what you expect. They might press Enter without typing anything, type "ten" instead of 10, or add extra spaces. Robust programs validate input and ask again politely instead of crashing.
In this lesson you'll read text and numbers, deal with the nullable result of ReadLine, write a loop that keeps asking until the input is valid, format output so it's easy to read, and read command-line arguments passed when the program starts.
Reading a line of text
Console.Write("What's your name? ");
string? name = Console.ReadLine();
Console.WriteLine($"Nice to meet you, {name}!");Console.Writekeeps the cursor on the same line, which suits prompts.ReadLinewaits for the user to press Enter and returns everything they typed, without the new line.- It returns
string?(a string that might be null), because input can end, for example when it's redirected from a file.Console.ReadLine() ?? ""replaces null with an empty string.
Reading numbers safely
Everything typed arrives as text, so numbers must be converted:
Console.Write("How many tickets? ");
string? text = Console.ReadLine();
if (int.TryParse(text, out int tickets) && tickets > 0)
{
Console.WriteLine($"Booking {tickets} tickets");
}
else
{
Console.WriteLine("Please enter a positive whole number.");
}TryParse returns false for empty, null or invalid text instead of throwing an exception, so it's the right choice for anything a person types. Use double.TryParse or decimal.TryParse for decimals.
Asking until the input is valid
Wrap the prompt in a loop that only ends when the input is acceptable:
int age;
while (true)
{
Console.Write("Age: ");
if (int.TryParse(Console.ReadLine(), out age) && age is >= 0 and <= 120)
break;
Console.WriteLine("Please enter an age between 0 and 120.");
}age is >= 0 and <= 120 is a pattern that checks a range in one readable expression. Putting this logic in a helper method, such as ReadInt(string prompt, int min, int max), keeps the rest of the program tidy.
Command-line arguments and extras
Values typed after the program name arrive in args: running dotnet run -- report.csv 10 gives args[0] == "report.csv" and args[1] == "10". Check args.Length before using them.
Console.ReadKey()reads a single key press without Enter, useful for menus.Console.ForegroundColor = ConsoleColor.Green;changes the text colour, andConsole.ResetColor()restores it.Console.Clear()clears the screen.
Reading until the input ends
ReadLine returns null when there's no more input. That happens when someone presses Ctrl+Z then Enter on Windows or Ctrl+D on macOS and Linux, and when input comes from a file. You can use it to process any number of lines:
int total = 0;
string? line;
while ((line = Console.ReadLine()) != null)
{
if (int.TryParse(line, out int n))
total += n;
}
Console.WriteLine($"Total: {total}");Run it with dotnet run < numbers.txt and the program reads the file as if someone had typed each line. Redirecting input like this is a quick way to test a console program without typing the same values over and over.
Error output and exit codes
Programs have two output streams. Console.WriteLine writes to standard output, and Console.Error.WriteLine writes to standard error. Both appear in the terminal, but when a user saves your output to a file with > results.txt, error messages still show on screen instead of mixing with the results.
A program also finishes with an exit code: 0 means success and anything else means something went wrong. Scripts and build tools check this number. With top-level statements, you can simply return it:
if (args.Length == 0)
{
Console.Error.WriteLine("Usage: report <file>");
return 1;
}
Console.WriteLine($"Reading {args[0]}");
return 0;In a classic program, declare static int Main(string[] args) and return the code in the same way.
C# Basics Syntax
Input and output
Console.Write("Prompt: ");
string input = Console.ReadLine() ?? "";
string clean = input.Trim();
if (int.TryParse(clean, out int n)) { /* use n */ }
if (decimal.TryParse(clean, out decimal amount)) { }
bool yes = clean.Equals("y", StringComparison.OrdinalIgnoreCase);
ConsoleKeyInfo key = Console.ReadKey();
Console.ForegroundColor = ConsoleColor.Red;
Console.ResetColor();
if (args.Length > 0) Console.WriteLine(args[0]);C# Basics Summary
- Console.Write prints a prompt; Console.ReadLine reads a line as string?.
- Use ?? to replace a null result with a default.
- Convert input with int.TryParse or decimal.TryParse, never assuming it's valid.
- Loop until input passes validation, with a clear message each time.
- Command-line arguments arrive in args; check args.Length first.
C# Basics Examples
Each example shows the code, the output it produces and what each part does.
A greeting with a default
Console.Write("Name (press Enter to skip): ");
string name = Console.ReadLine()?.Trim() ?? "";
if (string.IsNullOrWhiteSpace(name))
{
name = "friend";
}
Console.WriteLine($"Hello, {name}!");
Console.WriteLine($"Your name has {name.Length} letters.");Name (press Enter to skip): Grace
Hello, Grace!
Your name has 5 letters.Line-by-line explanation
- Line 2?. trims only if the result isn't null, and ?? supplies an empty string if it is.
- Lines 4 to 7An empty answer is replaced with a friendly default.
- Lines 9 to 10The output shows a run where the user typed Grace.
A validated number
int ReadInt(string prompt, int min, int max)
{
while (true)
{
Console.Write(prompt);
string? text = Console.ReadLine();
if (int.TryParse(text, out int value) && value >= min && value <= max)
{
return value;
}
Console.WriteLine($"Please enter a whole number from {min} to {max}.");
}
}
int qty = ReadInt("Quantity (1-10): ", 1, 10);
decimal price = 4.50m;
Console.WriteLine($"{qty} x {price:F2} = {qty * price:F2}");Quantity (1-10): lots
Please enter a whole number from 1 to 10.
Quantity (1-10): 25
Please enter a whole number from 1 to 10.
Quantity (1-10): 3
3 x 4.50 = 13.50Line-by-line explanation
- Line 1A local function keeps the validation logic in one reusable place.
- Line 3The loop only ends when return runs.
- Line 7Both the conversion and the range must pass.
- Line 15The caller gets a valid number without worrying about bad input.
- Line 17:F2 formats both amounts with two decimal places.
A yes or no menu with arguments
string user = args.Length > 0 ? args[0] : "guest";
Console.WriteLine($"Signed in as {user}");
Console.Write("Show the report? (y/n): ");
string answer = (Console.ReadLine() ?? "").Trim().ToLower();
if (answer is "y" or "yes")
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Sales: 1,204 orders this week");
Console.ResetColor();
}
else
{
Console.WriteLine("Report skipped.");
}Signed in as maria
Show the report? (y/n): YES
Sales: 1,204 orders this weekLine-by-line explanation
- Line 1The output shows a run started with dotnet run -- maria; without an argument the user is "guest".
- Line 5Trimming and lowercasing means "YES", " y " and "Yes" all work.
- Line 7The or pattern checks two values at once.
- Lines 9 to 11The text turns green, and ResetColor restores the normal colour.
Common C# Basics Mistakes
int.Parse on user input
int age = int.Parse(Console.ReadLine()); // crashes with FormatException on "abc"if (!int.TryParse(Console.ReadLine(), out int age))
{
Console.WriteLine("Please type a number.");
}Ignoring the possible null
string name = Console.ReadLine(); // warning CS8600: converting null to non-nullable type
Console.WriteLine(name.ToUpper()); // could throw NullReferenceExceptionstring name = Console.ReadLine() ?? "";
Console.WriteLine(name.ToUpper());Reading args without checking
string file = args[0]; // IndexOutOfRangeException when no argument is givenif (args.Length == 0)
{
Console.WriteLine("Usage: report <file>");
return;
}
string file = args[0];C# Basics in Real Projects
Console apps in practice
Developers write console tools to import data, run database migrations, clean up files and call APIs on a schedule. They take settings from command-line arguments, validate everything carefully, and print clear progress and errors. Libraries such as System.CommandLine and Spectre.Console add argument parsing, coloured tables and progress bars to the same basic ideas.
C# Basics FAQ
Why does Console.ReadLine return a nullable string?
ReadLine returns null when the input stream ends, for example when input is redirected from a file that has no more lines. The ? warns you about this so you handle it, either with ?? "" or a null check. When a person is typing interactively, you normally get a string, even an empty one.
How do I read an integer from the console in C#?
Read the line with Console.ReadLine() and convert it with int.TryParse, which returns false instead of throwing when the text isn't a valid number. Put the prompt in a loop so the user can try again after a mistake. int.Parse works too, but crashes with a FormatException on input such as "ten".
How do I pass command-line arguments with dotnet run?
Put them after a double dash: dotnet run -- input.txt 5. Everything after -- goes to your program in the args array, so args[0] is "input.txt" and args[1] is "5". Without the --, dotnet may try to treat them as its own options.
How do I wait for a key press before the console closes?
Add Console.ReadKey(); at the end of the program; it waits for one key and doesn't need Enter. This is mainly useful when a program is started by double-clicking, because the window closes as soon as the program ends. When you run from a terminal, the output stays visible anyway.
How do I print coloured text in the console?
Set Console.ForegroundColor to a value such as ConsoleColor.Red, write your text, then call Console.ResetColor() so later output goes back to normal. Console.BackgroundColor changes the background in the same way. Colours appear in most terminals but are lost when the output is redirected to a file.
C# Basics Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the line that reads what the user types.
string? text = Console.();
What type does Console.ReadLine return?
The user types 42 . What does this print?
bool ok = int.TryParse(Console.ReadLine(), out int n);
Console.WriteLine(ok ? n + 1 : -1);
What does Console.ReadLine() ?? "" do?
How do you pass "data.csv" to args[0]?
C# Basics Quiz
5 questions to check what you learned.
Which method prints without moving to a new line?
- Console.WriteLine
- Console.Write
- Console.Print
- Console.Out
Why use int.TryParse rather than int.Parse for user input?
- It's shorter
- It accepts decimals
- It reads from the console automatically
- It returns false for invalid text instead of throwing an exception
What does Console.ReadKey do?
- Reads a single key press
- Reads a whole line
- Reads a file
- Returns the last key typed earlier
What does
answer is "y" or "yes"check?- That answer contains y
- That answer is a bool
- That answer equals "y" or equals "yes"
- Nothing, it's invalid
How do you restore the console's normal colour after changing it?
- Console.Clear()
- Console.ResetColor()
- Console.ForegroundColor = null
- Restart the program