C# · Beginner

C# Syntax and Your First Program

8 min readUpdated September 24, 2026Every example verified

In short: A C# program is a list of statements that the compiler turns into a .NET executable. Since C# 9 a file can hold top-level statements without a class or a Main method: each statement ends with a semicolon, braces group statements into blocks, Console.WriteLine prints a line and Console.ReadLine reads one line of input as text.

How a C# program is built and run

C# is a compiled language. You write source in .cs files inside a project (a .csproj file that says which version of .NET to target), and dotnet run compiles the whole project and then executes it. Compilation is the reason C# reports many mistakes before the program runs at all: a misspelled name or a missing semicolon stops the build, and no output appears until every file compiles. Every example on this site is compiled with the .NET 8 SDK, which uses C# 12.

Since C# 9, one file in a project may contain top-level statements: plain statements written directly in the file with no surrounding class. The compiler wraps them in a hidden Program class with a Main method, so the two forms in the syntax block below are the same program. Older code and most books show the explicit form, and the dotnet new console template has produced the top-level form since .NET 6, so you need to be able to read both.

Four rules of the grammar shape everything. A statement ends with a semicolon, and line breaks do not matter to the compiler, so one statement may span several lines and two may share one. Braces { } group statements into a block that belongs to a loop, a condition, a method or a class. Names are case-sensitive: Console is a class, console is an unknown name. Comments start with // and run to the end of the line, or sit between /* and */, and the compiler ignores them.

Console.WriteLine(value) prints the value and then moves to the next line; Console.Write(value) prints without the line break, so the next output continues on the same line. Both accept text, numbers and most other values. To build a line from pieces, either join strings with + or use an interpolated string: $"Ticket for {name}" puts the value of name where the braces are. Interpolation is the form to reach for, because it reads like the finished line and converts numbers for you.

Console.ReadLine() reads one line of standard input and returns it as a string without the line break. It always returns text: a typed 42 arrives as the two characters 4 and 2, and turning that into a number is covered in variables and types. When the input has run out, ReadLine returns null instead of text. New .NET projects enable nullable reference types, so the compiler warns when a possibly null result is stored in a plain string; the ! after the call in the examples says that you know a line is there and silences the warning. That is fine for programs whose input format you control, which is every exercise here.

Console, Math and the other everyday types live in the System namespace. Older files start with using System; to bring it into scope. Projects created from the .NET 6 or later templates have implicit usings enabled, which adds System, System.Collections.Generic, System.Linq and a few others automatically, so the examples on this site leave the line out.

Syntax

 C# · syntax
// A program made of top-level statements (C# 9 and later)
Console.WriteLine("text");          // print a line
Console.Write("no line break");     // print and stay on the same line
Console.WriteLine($"Sum: {2 + 3}"); // interpolated string: expressions in braces
string line = Console.ReadLine()!;  // read one line of input as text

// The same program with an explicit class and entry point
using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("text");
    }
}

Only one file in a project may contain top-level statements, and in that file they must come before any class declarations.

Printing lines

Six statements that print, and one comment that does not.

 C#
Console.WriteLine("Millbrook Bakery");
Console.WriteLine("Open 7:00 to 15:00");
Console.Write("Loaves today: ");
Console.WriteLine(42);
Console.WriteLine("Sourdough " + "and " + "rye");
Console.WriteLine(6 * 7);
// This line is a comment and prints nothing

Output

Millbrook Bakery
Open 7:00 to 15:00
Loaves today: 42
Sourdough and rye
42

Each WriteLine ends its line, so the output has one line per call except where Console.Write left the cursor after Loaves today: ; the following WriteLine(42) finishes that line. WriteLine accepts a number directly, and 6 * 7 is calculated before it is printed. + between strings joins them into one string. The comment is dropped by the compiler and has no effect on the output.

Reading two lines of input

The program reads a passenger's name and destination, then builds three lines from them.

 C#
string name = Console.ReadLine()!;
string town = Console.ReadLine()!;
Console.WriteLine($"Ticket for {name}");
Console.WriteLine($"Destination: {town} ({town.Length} letters)");
Console.WriteLine("Have a good trip, " + name + ".");

Input given to the program: PriyaHalifax

Output

Ticket for Priya
Destination: Halifax (7 letters)
Have a good trip, Priya.

ReadLine returns the first line as the string Priya and the second as Halifax. {town.Length} inside the interpolated string shows that any expression fits in the braces; Length is the number of characters. The last line joins pieces with +, which works but is harder to read than the interpolated form above it. There are no prompts: when input comes from a file or a test rather than a person at a keyboard, a prompt would be printed into the output without anything typed after it, so the examples on this site do not prompt.

Common mistakes

  • Leaving out the semicolon

    Why it goes wrong: The build stops with error CS1002: ; expected. The compiler often reports it on the line after the incomplete one, because that is where it noticed something was wrong.

    Fix: End every statement with ;. A line that opens a block with { does not take one.

     C# · fix
    Console.WriteLine("ready");
  • Writing console.writeline in lower case

    Why it goes wrong: C# is case-sensitive; console is not the name of anything, so the build fails with error CS0103: The name 'console' does not exist in the current context.

    Fix: Type and method names in the .NET libraries start each word with a capital: Console.WriteLine, Console.ReadLine, Math.Round.

  • Putting a statement after a class in a top-level file

    Why it goes wrong: Top-level statements must all come before any type declaration in the file; a statement below a class gives error CS8803: Top-level statements must precede namespace and type declarations.

    Fix: Keep the statements at the top of the file and every class, record or interface below them.

     C# · fix
    Console.WriteLine(Helper.Twice(4));
    
    class Helper
    {
        public static int Twice(int n) => n * 2;
    }
  • Treating the result of ReadLine as a number

    Why it goes wrong: ReadLine returns a string. Console.ReadLine() + 1 with the input 41 produces the text 411, because + joins a string and a number into a string, and int x = Console.ReadLine(); does not compile at all.

    Fix: Convert the text with int.Parse (or int.TryParse when the input may be malformed).

     C# · fix
    int x = int.Parse(Console.ReadLine()!);
    Console.WriteLine(x + 1);

Console calls you will use in every program

CallWhat it doesGives back
Console.WriteLine(x)prints x, then a line breaknothing
Console.WriteLine()prints an empty linenothing
Console.Write(x)prints x with no line breaknothing
Console.ReadLine()reads the next line of input, without its line breaka string, or null when the input has ended

Where you use this

Every exercise on this site, and a great many real tools, have the same shape: read the input, compute something, print the result. A script that converts a spreadsheet export, a health check that a server runs every minute, a command-line utility that renames files: each is a console program that starts at its first statement and ends after its last. Writing that shape precisely, with the right punctuation and the right print method, is what lets you spend your attention on the logic in the middle. The snippet reads one line, computes with it and prints one line; the middle step is where every later lesson adds something.

 C# · in practice
string item = Console.ReadLine()!;
string message = $"Received: {item}";
Console.WriteLine(message);

Key points

  • A C# file is compiled before it runs; a single syntax error stops the whole build.
  • Top-level statements (C# 9 and later) let a file start with statements; the compiler generates the Program class and Main for you.
  • Every statement ends with ;, braces group statements into blocks, and names are case-sensitive.
  • Console.WriteLine prints a line; Console.Write prints without a line break.
  • Console.ReadLine() returns the next line as a string, or null when the input is exhausted.
  • $"...{expression}..." builds a line from values; prefer it to joining with +.

Try it yourself

The program reads a dish name and prints one line. Change it so that it also reads a second line holding a table number, and prints a single line in the form Table 7: lentil soup using string interpolation.

Your program
string dish = Console.ReadLine()!;
Console.WriteLine("Order: " + dish);
Input the program receives: lentil soup ↵ 7
Expected output: Table 7: lentil soup

Practise this

Open the C# playground

Frequently asked questions

Do I need a Main method in C#?

Not since C# 9. One file in a project may contain top-level statements, and the compiler generates the Main method around them; every other file must still use classes. Writing static void Main() inside a class Program yourself is still valid and is what most existing code looks like, so you should recognise both forms.

What is the difference between Console.Write and Console.WriteLine?

WriteLine prints its argument and then a line break, so the next output starts on a new line. Write prints the argument only, so the next output continues on the same line. Use Write to build one line from several calls, for instance a label followed by a value, and WriteLine for the last piece.

Why does the compiler warn that Console.ReadLine() may be null?

ReadLine returns null when there is no more input, for example when a redirected input file has ended, so its return type is string?, a string that may be null. With nullable reference types enabled, the default in new projects, storing it in a plain string produces a warning. Appending ! tells the compiler you know a line will be there. Checking for null with if (line == null) or supplying a fallback with ?? handles the end of input properly, which matters when a program reads until the input runs out.

Progress is stored only in this browser.

How this page was checked. Every program on it was run with .NET SDK 8.0 at build time by the publishing checks, and the output shown is what it printed. Running C# inside the browser is not available yet, so the Run button is absent rather than pretending; copy the code and run it with .NET SDK 8.0 locally.