Main() return values (C# Programming Guide)

The Main method can return void:

static void Main()
{
    //...
}

It can also return an int:

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

If the return value from Main is not used, returning void allows for slightly simpler code. However, returning an integer enables the program to communicate status information to other programs or scripts that invoke the executable file. The return value from Main is treated as the exit code for the process. The following example shows how the return value from Main can be accessed.

Example

This example uses .NET Core command line tools. If you are unfamilar with .NET Core command line tools, you can learn about them in this Get started topic.

Modify the Main method in program.cs as follows:

// Save this program as MainReturnValTest.cs.
class MainReturnValTest
{
    static int Main()
    {
        //...
        return 0;
    }
}

When a program is executed in Windows, any value returned from the Main function is stored in an environment variable. This environment variable can be retrieved using ERRORLEVEL from a batch file, or $LastExitCode from powershell.

You can build the application 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 will report success. However, if you change MainReturnValTest.cs to return a non-zero value and then re-compile the program, subsequent execution of the powershell script will report failure.

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

Sample output

Execution succeeded
Return value = 0

Async Main return values

Async Main return values move the boilerplate code necessary for calling asynchronous methods in Main to code generated by the compiler. Previously, you would need to write this construct to call asynchronous code and ensure your program ran until the asynchronous operation completed:

public static void Main()
{
    AsyncConsoleWork().GetAwaiter().GetResult();
}

private static async Task<int> AsyncConsoleWork()
{
    // Main body here
    return 0;
}

Now, this can be replaced by:

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

The advantage of the new syntax is that the compiler always generates the correct code.

Compiler generated 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 used async modifier on the Main method, the compiler would generate the same code.

See also

C# Programming Guide C# Reference Main() and Command-Line Arguments How to: Display Command Line Arguments How to: Access Command-Line Arguments Using foreach