This lesson will get you started with C# by introducing a few very simple programs. Here are the objectives of this lesson:
- Understand the basic structure of a C# program.
- Obtain a basic familiarization of what a “Namespace” is.
- Obtain a basic understanding of what a Class is.
- Learn what the Main method does.
- Learn how to obtain command-line input.
- Learn about console input/output (I/O).
A Simple C# Program
There are basic elements that all C# executable programs have and that’s what we’ll concentrate on for this first lesson, starting off with a simple C# program. After reviewing the code in Listing 1-1, I’ll explain the basic concepts that will follow for all C# programs we will write throughout this tutorial. Please see Listing 1-1 to view this first program.
Warning: C# is case-sensitive.
Listing 1-1. A Simple Welcome Program: Welcome.cs
// Import names from the System namespace.
using System;
// Program start class.
class WelcomeCSS
{
// Main begins program execution.
static void Main()
{
// Write to the console.
Console.WriteLine("Welcome to the C# Station Tutorial!");
}
}
Run this lesson with the .NET SDK
Install the .NET 10 SDK for your supported Windows, macOS, or Linux system using Microsoft’s installation instructions. The SDK includes the tools to build and run C# programs. See the tutorial contents and setup guide for the lesson sequence.
Open PowerShell or Command Prompt on Windows, or a terminal on macOS or Linux. These commands show which SDK is active and create a project. The version should start with 10.. If it does not, check your SDK installation and any global.json file in the directory or its parents:
dotnet --version
dotnet new console --framework net10.0 --name Welcome
cd Welcome
Replace all the contents of Program.cs with Listing 1-1 and save it. Then run:
dotnet run
Welcome to the C# Station Tutorial!
Replace Program.cs with one complete listing at a time. Do not add the listing below the template’s existing top-level statements. Modern templates use top-level statements, which let the compiler generate an entry point; this lesson uses an explicit class and Main to explain program structure.
The program has a using directive, a class, a Main method, and a statement. The file name and class name can differ. dotnet run builds the project and runs it in your current terminal, where the output remains after the program exits.
The first thing you should be aware of is that C# is case-sensitive. The word “Main” is not the same as its lowercase spelling, “main”. They are different identifiers. If you are coming from a language that is not case sensitive, this will trip you up several times until you become accustomed to it.
The using directive, using System;, indicates that you are referencing the System namespace. Namespaces contain groups of code that can be called upon by C# programs. With the using System; directive, you are telling your program that it can reference the code in the System namespace without pre-pending the word System to every reference. I’ll discuss this in more detail in Lesson 06: Namespaces, which is dedicated specifically to namespaces.
The class declaration, class WelcomeCSS, contains the data and method definitions that your program uses to execute. A class is one of a few different types of elements your program can use to describe objects, such as structs, interfaces, delegates, and enums, which will be discussed in more detail in Lesson 12: Structs, Lesson 13: Interfaces, Lesson 14: Delegates, and Lesson 17: Enums, respectively. This particular class has no data, but it does have one method. This method defines the behavior of this class (or what it is capable of doing). I’ll discuss classes more in Lesson 07: Introduction to Classes. We’ll be covering a lot of information about classes throughout this tutorial.
The one method within the WelcomeCSS class tells what this class will do when executed. In this explicit-entry-point form, the runtime starts the program by calling Main. Main is often called the “entry point” and if you ever receive a compiler error message saying that it can’t find the entry point, it means that you tried to compile an executable program without a suitable entry point. Top-level statements provide an entry point automatically.
A static modifier precedes the word Main, meaning that this method belongs to the type rather than an instance of the class. The runtime can call it without creating a WelcomeCSS object. I’ll tell you more about classes, objects, and instances in Lesson 07: Introduction to Classes.
Every ordinary method must have a return type. In this case, it is void, which means that Main does not return a value. Every method also has a parameter list following its name with zero or more parameters between parenthesis. For simplicity, we did not add parameters to Main. Later in this lesson, you’ll see what type of parameter the Main method can have. You’ll learn more about methods in Lesson 05: Methods.
The Main method specifies its behavior with the Console.WriteLine(…) statement. Console is a class in the System namespace. WriteLine(…) is a method in the Console class. We use the “.”, dot, operator to separate subordinate program elements. Note that we could also write this statement as System.Console.WriteLine(…). This follows the pattern “namespace.class.method” as a fully qualified statement. Had we left out the using System declaration at the top of the program, it would have been mandatory for us to use the fully qualified form System.Console.WriteLine(…). This statement is what causes the string, “Welcome to the C# Station Tutorial!” to print on the console screen.
Observe that comments are marked with “//”. These are single line comments, meaning that they are valid until the end-of-line. If you wish to span multiple lines with a comment, begin with “/*” and end with “*/”. Everything in between is part of the comment. Comments are ignored when your program compiles. They are there to document what your program does in plain English (or the native language you speak with every day).
Simple statements such as method calls end with a “;”, semicolon. Classes and methods begin with “{“, left curly brace, and end with a “}”, right curly brace. Any statements within and including “{” and “}” define a block. Blocks define the scope (or lifetime and visibility) of program elements.
Accepting Command-Line Input
In the previous example, you simply ran the program and it produced output. However, many programs are written to accept command-line input. This makes it easier to write automated scripts that can invoke your program and pass information to it. If you look at many of the programs, including Windows OS utilities, that you use every day; most of them have some type of command-line interface. For example, if you type Notepad.exe MyFile.txt (assuming the file exists), then the Notepad program will open your MyFile.txt file so you can begin editing it. You can make your programs accept command-line input also, as shown in Listing 1-2, which shows a program that accepts a name from the command line and writes it to the console.
Replace Program.cs with Listing 1-2. It checks whether an argument exists before reading args[0], so running without a name prints usage instructions.
Listing 1-2. Getting Command-Line Input: NamedWelcome.cs
using System;
class NamedWelcome
{
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Usage: dotnet run -- YourName");
return;
}
Console.WriteLine("Hello, {0}!", args[0]);
Console.WriteLine("Welcome to the C# Station Tutorial!");
}
}
From the project directory, run:
dotnet run -- Joe
The -- separates application arguments from dotnet run options. For a name containing spaces, use dotnet run -- "Mary Jane". Without a name, dotnet run prints Usage: dotnet run -- YourName and ends without accessing an absent argument. This example uses only the first argument.
return; ends Main early. The length check uses an if statement, covered in Lesson 3: Selection. For other error conditions, continue to Lesson 15: Introduction to Exception Handling.
In Listing 1-2, you’ll notice an entry in the Main method’s parameter list. The parameter name is args, which you’ll use to refer to the parameter later in your program. The string[] expression defines the type of parameter that args are. The string type holds characters. These characters could form a single word or multiple words. The “[]”, square brackets denote an Array, which is like a list. Therefore, the type of the args parameter is a list of words from the command-line. Anytime you add string[] args to the parameter list of the Main method, the runtime provides the command-line arguments in args. By reading args, you have access to all arguments, minus the application name, that was typed on the command-line.
You’ll also notice an additional Console.WriteLine(…) statement within the Main method. The argument list in this statement is different than before. It has a formatted string with a “{0}” parameter embedded in it. The first parameter in a formatted string begins at number 0, the second is 1, and so on. The “{0}” parameter means that the next argument following the end quote will determine what goes in that position. Hold that thought, and now we’ll look at the next argument following the end quote.
The args[0] argument refers to the first string in the args array. The first element of an Array is number 0, the second is number 1, and so on. For example, if I typed dotnet run -- Joe on the command-line, the value of args[0] would be “Joe”. This is a little tricky because you know that you typed dotnet run -- Joe, but args contains only the application arguments. Neither the executable name nor dotnet run nor the -- separator appears in args.
Returning to the embedded “{0}” parameter in the formatted string: Since args[0] is the first argument, after the formatted string, of the Console.WriteLine() statement, its value will be placed into the first embedded parameter of the formatted string. When this command is executed, the value of args[0], which is “Joe” will replace “{0}” in the formatted string. Upon execution of the command-line with dotnet run -- Joe, the output will be as follows:
Hello, Joe! Welcome to the C# Station Tutorial!
Interacting via the Command-Line
Besides command-line input, another way to provide input to a program is via the Console. Typically, it works like this: You prompt the user for some input, they type something in and press the Enter key, and you read their input and take some action. Listing 1-3 shows how to obtain interactive input from the user.
Listing 1-3. Getting Interactive Input: InteractiveWelcome.cs
-
using System; class InteractiveWelcome { public static void Main() { Console.Write("What is your name?: "); Console.Write("Hello, {0}! ", Console.ReadLine()); Console.WriteLine("Welcome to the C# Station Tutorial!"); } }
Replace Program.cs with Listing 1-3 and run dotnet run. Type your name and press Enter. Console.ReadLine() returns null if the input stream ends, so use string? when storing its result with nullable reference analysis enabled.
In Listing 1-3, the Main method doesn’t have any parameters — mostly because it isn’t necessary this time. Notice also that I prefixed the Main method declaration with the public keyword. The public keyword means that any class outside of this one can access that class member. For Main, it doesn’t matter because the runtime can use either a public or private entry point, but as you go through this tutorial, you’ll see how you can create classes with members that must be public so they can be used. The default access is private, which means that only members inside of the same class can access it. Keywords such as public and private are referred to as access modifiers. Lesson 19: Encapsulation discusses access modifiers in more depth.
There are three statements inside of Main and the first two are different from the third. They are Console.Write(…) instead of Console.WriteLine(…). The difference is that the Console.Write(…) statement writes to the console and stops on the same line, but the Console.WriteLine(…) goes to the next line after writing to the console.
The first statement simply writes “What is your name?: ” to the console.
The second statement doesn’t write anything until its arguments are properly evaluated. The first argument after the formatted string is Console.ReadLine(). This causes the program to wait for user input at the console. After the user types input, their name in this case, they must press the Enter key. The return value from this method replaces the “{0}” parameter of the formatted string and is written to the console. This line could have also been written like this:
string? name = Console.ReadLine();
Console.Write("Hello, {0}! ", name);
The last statement writes to the console as described earlier. Upon execution of the command-line with dotnet run, the output will be as follows:
If you enter Joe, the terminal interaction is:
What is your name?: Joe
Hello, Joe! Welcome to the C# Station Tutorial!
The first line includes the name you type. The prompt itself is What is your name?: .
Summary
Now you know the basic structure of a C# program. using statements let you reference a namespace and allow code to have shorter and more readable notation. The Main method is the entry point to start a C# program. You can capture command-line input when an application is run by reading items from a string[] (string array) parameter to your Main method. Interactive I/O can be performed with the ReadLine, Write and WriteLine methods of the Console class.
This is just the beginning, the first of many lessons. I invite you back to take Lesson 2: Operators, Types, and Variables.
Current .NET references
See Microsoft’s dotnet run reference and Main and command-line arguments guide.