C# User Input

User input lets a C# program receive text typed by a person while the program is running. It matters because programs become more useful when they can ask questions, read choices, and calculate results from values that are not known when the code is written. In console applications, the usual tool is Console.ReadLine(), often paired with Console.Write or Console.WriteLine prompts.

Overview: How C# User Input Works

A console program has standard input, usually called stdin. When you type into a terminal and press Enter, that line of text is made available to the running program. C# exposes this through the .NET System.Console class. Console.ReadLine() waits for a complete line, removes the line ending, and returns the characters as a string?.

The question mark in string? is important in modern C#. It means the method can return either a string or null. In an interactive terminal, you normally get a string after the user presses Enter. In redirected input, automated tests, or the end of a file, there may be no more line to read, so ReadLine can return null. Good input code either checks for null, supplies a default with ??, or validates before using the value.

ReadLine always reads text. If the user types 42, your program receives the string "42", not an int. To use numeric input, parse or convert it. The safer beginner-friendly pattern is int.TryParse, double.TryParse, or decimal.TryParse, because those methods report failure instead of crashing the program with an exception.

A prompt is output shown before reading input. Use Console.Write when you want the user to type on the same line as the prompt, and Console.WriteLine when the answer should appear on the next line. The examples below use Console.SetIn with StringReader only to make the lessons compile and run predictably in an automated checker. In a real interactive program, you normally remove Console.SetIn and let the user type into the console.

Syntax

Console.Write("Enter your name: ");
string? name = Console.ReadLine();
Console.WriteLine($"Hello, {name ?? "guest"}!");
Part Meaning
Console.Write(...) Prints a prompt without moving to a new line.
Console.ReadLine() Reads one full line from standard input and returns string?.
string? A string variable that is allowed to hold null.
?? Uses a fallback value when the input is null.
TryParse Attempts to convert text to a number without throwing on bad input.

The basic flow is prompt, read, validate or convert, then use the value. Keep those steps visible in beginner programs. It makes input code easier to debug because you can see exactly where text becomes a typed value.

Examples

Reading a Name

using System;
using System.IO;

class Program
{
    static void Main()
    {
        Console.SetIn(new StringReader("Maya
"));

        Console.Write("Enter your name: ");
        string? name = Console.ReadLine();

        Console.WriteLine($"Welcome, {name}!");
    }
}

Output:

Enter your name: Welcome, Maya!

The prompt uses Write, so the answer appears on the same line in a real terminal. ReadLine reads everything up to Enter and stores it in name. The program then inserts that value into an interpolated string.

Reading and Parsing a Whole Number

using System;
using System.IO;

class Program
{
    static void Main()
    {
        Console.SetIn(new StringReader("17
"));

        Console.Write("Enter your age: ");
        string? text = Console.ReadLine();

        if (int.TryParse(text, out int age))
        {
            Console.WriteLine($"Next year you will be {age + 1}.");
        }
        else
        {
            Console.WriteLine("Please enter a whole number.");
        }
    }
}

Output:

Enter your age: Next year you will be 18.

The variable text contains the characters the user typed. int.TryParse tries to convert those characters to an int. If it succeeds, the parsed number is assigned to age and the program can do arithmetic with it. If it fails, the else branch gives a clear message instead of stopping the program.

Collecting Several Values

using System;
using System.Globalization;
using System.IO;

class Program
{
    static void Main()
    {
        Console.SetIn(new StringReader("Alex
3
12.50
"));

        Console.Write("Customer name: ");
        string customer = Console.ReadLine() ?? "Guest";

        Console.Write("Quantity: ");
        string? quantityText = Console.ReadLine();

        Console.Write("Unit price: ");
        string? priceText = Console.ReadLine();

        bool validQuantity = int.TryParse(quantityText, out int quantity);
        bool validPrice = decimal.TryParse(priceText, NumberStyles.Number, CultureInfo.InvariantCulture, out decimal unitPrice);

        if (validQuantity && validPrice && quantity > 0)
        {
            decimal total = quantity * unitPrice;
            Console.WriteLine($"Order for {customer}");
            Console.WriteLine($"Total: {total.ToString("F2", CultureInfo.InvariantCulture)}");
        }
        else
        {
            Console.WriteLine("The order could not be calculated.");
        }
    }
}

Output:

Customer name: Quantity: Unit price: Order for Alex
Total: 37.50

This example reads three separate lines: a name, a quantity, and a price. It uses ?? to provide a fallback customer name if input ends early. It validates both numeric values before calculating the total, and it uses invariant culture for the decimal example so the expected output is stable.

How Input Works Step by Step

  1. Your code prints a prompt through Console.Write or Console.WriteLine.
  2. The program reaches Console.ReadLine() and asks the console input stream for the next complete line.
  3. The runtime waits until a line is available. In an interactive console, that usually means the user presses Enter.
  4. The line ending is removed. The remaining characters are returned as a string, or null is returned if there is no more input.
  5. Your code checks, trims, parses, compares, or stores the returned text.

Internally, the console input stream works with text rather than C# numeric types. That is why parsing is a separate step. This separation is useful: it lets you decide which inputs are valid, what message to show when input is wrong, and whether to keep asking or use a default.

Common Mistakes

Assigning Possibly Null Input to string

using System;
using System.IO;

class Program
{
    static void Main()
    {
        Console.SetIn(new StringReader("yes
"));

        Console.Write("Continue? ");
        string answer = Console.ReadLine();

        Console.WriteLine($"You typed: {answer}");
    }
}

Output:

Continue? You typed: yes

This can compile with a nullable warning because ReadLine returns string?, not guaranteed string. Treat the warning as useful information. Correct it by checking for null or using a fallback.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        Console.SetIn(new StringReader("yes
"));

        Console.Write("Continue? ");
        string answer = Console.ReadLine() ?? "";

        Console.WriteLine($"You typed: {answer}");
    }
}

Output:

Continue? You typed: yes

Using Parse When Input May Be Wrong

using System;
using System.IO;

class Program
{
    static void Main()
    {
        Console.SetIn(new StringReader("8
"));

        Console.Write("Count: ");
        int count = int.Parse(Console.ReadLine() ?? "0");
        Console.WriteLine($"Double: {count * 2}");
    }
}

Output:

Count: Double: 16

This works only while the input is valid. If the user types eight, int.Parse throws a runtime exception. For user input, prefer TryParse unless invalid input truly should stop the program.

using System;
using System.IO;

class Program
{
    static void Main()
    {
        Console.SetIn(new StringReader("eight
"));

        Console.Write("Count: ");
        string? text = Console.ReadLine();

        if (int.TryParse(text, out int count))
        {
            Console.WriteLine($"Double: {count * 2}");
        }
        else
        {
            Console.WriteLine("Count must be a whole number.");
        }
    }
}

Output:

Count: Count must be a whole number.

Best Practices

  • Use Console.Write for short prompts where the answer should appear on the same line.
  • Remember that Console.ReadLine() returns string?; handle null deliberately.
  • Trim input with Trim() when accidental leading or trailing spaces should not matter.
  • Use TryParse for numbers entered by users.
  • Give specific error messages, such as Quantity must be a whole number, instead of vague failure text.
  • For money, prefer decimal over double.
  • Keep prompting and parsing separate so each step is easy to read and test.
  • Do not trust input just because it came from a console; validate ranges and required fields.

Practice Exercises

  1. Ask for a first name and last name, then print a greeting using both values. Handle missing input by using Guest.
  2. Ask for two whole numbers. Use int.TryParse for both and print their sum only when both are valid.
  3. Ask for a temperature in Celsius as a decimal number. Convert it to Fahrenheit with celsius * 9 / 5 + 32 and print one decimal place.

Summary

  • Console.ReadLine() reads one line of console input as text.
  • The return type is string?, so input may be a string or null.
  • All console input starts as text; convert it before using it as a number.
  • TryParse is safer than Parse for user-entered values.
  • Good input code prompts clearly, validates carefully, and handles bad or missing input without surprising crashes.