Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Top-level statements - programs without
You don't have to explicitly include a Main method in a console application project. Instead, you can use the top-level statements feature to minimize the code you have to write.
Top-level statements allow you to write executable code directly at the root of a file, eliminating the need for wrapping your code in a class or method.
This means you can create programs without the ceremony of a Program class and a Main method.
In this case, the compiler generates a Program class with an entry point method for the application. The name of the generated method isn't Main, it's an implementation detail that your code can't reference directly.
Here's a Program.cs file that is a complete C# program:
Console.WriteLine("Hello World!");
Top-level statements let you write simple programs for small utilities such as Azure Functions and GitHub Actions. They also make it simpler for new C# programmers to get started learning and writing code.
The following sections explain the rules on what you can and can't do with top-level statements.
Only one top-level file
An application must have only one entry point. A project can have only one file with top-level statements. Putting top-level statements in more than one file in a project results in the following compiler error:
CS8802 Only one compilation unit can have top-level statements.
A project can have any number of source code files that don't have top-level statements.
No other entry points
You can explicitly write a Main method, but it can't function as an entry point. The compiler issues the following warning:
CS7022 The entry point of the program is global code; ignoring 'Main()' entry point.
In a project with top-level statements, you can't use the -main compiler option to select the entry point, even if the project has one or more Main methods.
using directives
For the single file containing top-level statements, using directives must come first in that file, as in this example:
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;
Global namespace
Top-level statements are implicitly in the global namespace.
Namespaces and type definitions
A file with top-level statements can also contain namespaces and type definitions, but they must come after the top-level statements. For example:
MyClass.TestMethod();
MyNamespace.MyClass.MyMethod();
public class MyClass
{
public static void TestMethod()
{
Console.WriteLine("Hello World!");
}
}
namespace MyNamespace
{
class MyClass
{
public static void MyMethod()
{
Console.WriteLine("Hello World from MyNamespace.MyClass.MyMethod!");
}
}
}
args
Top-level statements can reference the args variable to access any command-line arguments that were entered. The args variable is never null but its Length is zero if no command-line arguments were provided. For example:
if (args.Length > 0)
{
foreach (var arg in args)
{
Console.WriteLine($"Argument={arg}");
}
}
else
{
Console.WriteLine("No arguments");
}
await
Use await to call an async method. For example:
Console.Write("Hello ");
await Task.Delay(5000);
Console.WriteLine("World!");
Exit code for the process
To return an int value when the application ends, use the return statement as you would in a Main method that returns an int. For example:
string? s = Console.ReadLine();
int returnValue = int.Parse(s ?? "-1");
return returnValue;
Implicit entry point method
The compiler generates a method to serve as the program entry point for a project with top-level statements. The signature of the method depends on whether the top-level statements contain the await keyword or the return statement. The following table shows what the method signature looks like, using the method name Main in the table for convenience.
| Top-level code contains | Implicit Main signature |
|---|---|
await and return |
static async Task<int> Main(string[] args) |
await |
static async Task Main(string[] args) |
return |
static int Main(string[] args) |
No await or return |
static void Main(string[] args) |
Starting 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 directive as the first line (Unix shells only).
C# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.