Editéieren

Deelen iwwer


Main() and command-line arguments

The runtime calls the Main method when you start a C# application. The Main method is the entry point of a C# application.

A C# program can have only one entry point. If you have more than one class with a Main method, you must use the StartupObject compiler option when you compile your program to specify which Main method serves as the entry point. For more information, see StartupObject (C# Compiler Options). The following example displays the number of command line arguments as its first action:

class TestClass
{
    static void Main(string[] args)
    {
        Console.WriteLine(args.Length);
    }
}

You can also use top-level statements in one file as the entry point for your application. Like the Main method, top-level statements can return values and access command-line arguments. For more information, see Top-level statements. The following example uses a foreach loop to display the command-line arguments by using the args variable, and at the end of the program returns a success code (0):

using System.Text;

StringBuilder builder = new();
builder.AppendLine("The following arguments are passed:");

foreach (var arg in args)
{
    builder.AppendLine($"Argument={arg}");
}

Console.WriteLine(builder.ToString());

return 0;

Beginning with C# 14, programs can be file-based apps, where a single file contains the program. You run file-based apps by using the command dotnet <file.cs>, or by using the #!/usr/bin/env dotnet run directive as the first line (Unix shells only).

Overview

  • The Main method is the entry point of an executable program. It's where the program control starts and ends.
  • You must declare Main inside a class or struct. The enclosing class can be static.
  • Main must be static.
  • Main can have any access modifier.
  • Main can return void, int, Task, or Task<int>.
  • If and only if Main returns a Task or Task<int>, the declaration of Main can include the async modifier. This rule specifically excludes an async void Main method.
  • You can declare the Main method with or without a string[] parameter that contains command-line arguments. When using Visual Studio to create Windows applications, you can add the parameter manually or else use the GetCommandLineArgs() method to obtain the command-line arguments. Parameters are zero-indexed command-line arguments. Unlike C and C++, the name of the program isn't treated as the first command-line argument in the args array, but it's the first element of the GetCommandLineArgs() method.

The following list shows the most common Main declarations:

static void Main() { }
static int Main() { }
static void Main(string[] args) { }
static int Main(string[] args) { }
static async Task Main() { }
static async Task<int> Main() { }
static async Task Main(string[] args) { }
static async Task<int> Main(string[] args) { }

The preceding examples don't specify an access modifier, so they're implicitly private by default. You can specify any explicit access modifier.

Tip

By using async and Task or Task<int> return types, you simplify program code when console applications need to start and await asynchronous operations in Main.

Main() return values

You can return an int from the Main method by defining the method in one of the following ways:

Main declaration Main method code
static int Main() No use of args or await
static int Main(string[] args) Uses args but not await
static async Task<int> Main() Uses await but not args
static async Task<int> Main(string[] args) Uses args and await

If the return value from Main isn't used, returning void or Task allows for slightly simpler code.

Main declaration Main method code
static void Main() No use of args or await
static void Main(string[] args) Uses args but not await
static async Task Main() Uses await but not args
static async Task Main(string[] args) Uses args and await

However, returning int or Task<int> enables the program to communicate status information to other programs or scripts that invoke the executable file.

The following example shows how the exit code for the process can be accessed.

This example uses .NET Core command-line tools. If you're unfamiliar with .NET Core command-line tools, you can learn about them in this get-started article.

Create a new application by running dotnet new console. Modify the Main method in Program.cs as follows:

class MainReturnValTest
{
    static int Main()
    {
        //...
        return 0;
    }
}

Remember to save this program as MainReturnValTest.cs.

When you execute a program in Windows, the system stores any value returned from the Main function in an environment variable. You can retrieve this environment variable by using ERRORLEVEL from a batch file, or $LastExitCode from PowerShell.

You can build the application by using the dotnet CLI dotnet build command.

Next, create a PowerShell script to run the application and display the result. Paste the following code into a text file and save it as test.ps1 in the folder that contains the project. Run the PowerShell script by typing test.ps1 at the PowerShell prompt.

Because the code returns zero, the batch file reports success. However, if you change MainReturnValTest.cs to return a nonzero value and then recompile the program, subsequent execution of the PowerShell script reports failure.

dotnet run
if ($LastExitCode -eq 0) {
    Write-Host "Execution succeeded"
} else
{
    Write-Host "Execution Failed"
}
Write-Host "Return value = " $LastExitCode
Execution succeeded
Return value = 0

Async Main return values

When you declare an async return value for Main, the compiler generates the boilerplate code for calling asynchronous methods in Main:

class Program
{
    static async Task<int> Main(string[] args)
    {
        return await AsyncConsoleWork();
    }

    private static async Task<int> AsyncConsoleWork()
    {
        return 0;
    }
}

In both examples, the main body of the program is within the body of the AsyncConsoleWork() method.

An advantage of declaring Main as async is that the compiler always generates the correct code.

When the application entry point returns a Task or Task<int>, the compiler generates a new entry point that calls the entry point method declared in the application code. Assuming that this entry point is called $GeneratedMain, the compiler generates the following code for these entry points:

  • static Task Main() results in the compiler emitting the equivalent of private static void $GeneratedMain() => Main().GetAwaiter().GetResult();.
  • static Task Main(string[]) results in the compiler emitting the equivalent of private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();.
  • static Task<int> Main() results in the compiler emitting the equivalent of private static int $GeneratedMain() => Main().GetAwaiter().GetResult();.
  • static Task<int> Main(string[]) results in the compiler emitting the equivalent of private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();.

Note

If the examples use the async modifier on the Main method, the compiler generates the same code.

Command-line arguments

You can send arguments to the Main method by defining the method in one of the following ways:

Main declaration Main method code
static void Main(string[] args) No return value or await
static int Main(string[] args) Returns a value but doesn't use await
static async Task Main(string[] args) Uses await but doesn't return a value
static async Task<int> Main(string[] args) Return a value and uses await

If you don't use the arguments, you can omit args from the method declaration for slightly simpler code:

Main declaration Main method code
static void Main() No return value or await
static int Main() Returns a value but doesn't use await
static async Task Main() Uses await but doesn't return a value
static async Task<int> Main() Returns a value and uses await

Note

You can also use Environment.CommandLine or Environment.GetCommandLineArgs to access the command-line arguments from any point in a console or Windows Forms application. To enable command-line arguments in the Main method declaration in a Windows Forms application, you must manually modify the declaration of Main. The code generated by the Windows Forms designer creates Main without an input parameter.

The parameter of the Main method is a String array that represents the command-line arguments. Usually, you determine whether arguments exist by testing the Length property, for example:

if (args.Length == 0)
{
    System.Console.WriteLine("Please enter a numeric argument.");
    return 1;
}

Tip

The args array can't be null. So, it's safe to access the Length property without null checking.

You can also convert the string arguments to numeric types by using the Convert class or the Parse method. For example, the following statement converts the string to a long number by using the Parse method:

long num = Int64.Parse(args[0]);

It's also possible to use the C# type long, which aliases Int64:

long num = long.Parse(args[0]);

You can also use the Convert class method ToInt64 to do the same thing:

long num = Convert.ToInt64(s);

For more information, see Parse and Convert.

Tip

Parsing command-line arguments can be complex. Consider using the System.CommandLine library (currently in beta) to simplify the process.

The following example shows how to use command-line arguments in a console application. The application takes one argument at run time, converts the argument to an integer, and calculates the factorial of the number. If no arguments are supplied, the application issues a message that explains the correct usage of the program.

To compile and run the application from a command prompt, follow these steps:

  1. Paste the following code into any text editor, and then save the file as a text file with the name Factorial.cs.
public class Functions
{
    public static long Factorial(int n)
    {
        // Test for invalid input.
        if ((n < 0) || (n > 20))
        {
            return -1;
        }

        // Calculate the factorial iteratively rather than recursively.
        long tempResult = 1;
        for (int i = 1; i <= n; i++)
        {
            tempResult *= i;
        }
        return tempResult;
    }
}

class MainClass
{
    static int Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("Please enter a numeric argument.");
            Console.WriteLine("Usage: Factorial <num>");
            return 1;
        }

        int num;
        bool test = int.TryParse(args[0], out num);
        if (!test)
        {
            Console.WriteLine("Please enter a numeric argument.");
            Console.WriteLine("Usage: Factorial <num>");
            return 1;
        }

        long result = Functions.Factorial(num);

        if (result == -1)
            Console.WriteLine("Input must be >= 0 and <= 20.");
        else
            Console.WriteLine($"The Factorial of {num} is {result}.");

        return 0;
    }
}

At the beginning of the Main method, the program tests if input arguments weren't supplied by comparing the length of the args argument to 0 and displays the help if no arguments are found.
If arguments are provided (args.Length is greater than 0), the program tries to convert the input arguments to numbers. This example throws an exception if the argument isn't a number.
After factorial is calculated (stored in result variable of type long), the verbose result is printed depending on the result variable.

  1. From the Start screen or Start menu, open a Visual Studio Developer Command Prompt window, and then navigate to the folder that contains the file that you created.

  2. To compile the application, enter the following command:

    dotnet build

    If your application has no compilation errors, the build process creates a binary file named Factorial.dll.

  3. Enter the following command to calculate the factorial of 3:

    dotnet run -- 3

  4. If you enter 3 on the command line as the program's argument, the output reads: The factorial of 3 is 6.

Note

When running an application in Visual Studio, specify command-line arguments in the Debug Page, Project Designer.

C# language specification

For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

See also