Top-level statements remove unnecessary ceremony from many applications. Consider the canonical "Hello World!" program:
using System; namespace HelloWorld { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); } } }
There’s only one line of code that does anything. With top-level statements, you can replace all that boilerplate with the using
statement and the single line that does the work:
using System;
Console.WriteLine("Hello World!");
If you wanted a one-line program, you could remove the using
directive and use the fully qualified type name:
System.Console.WriteLine("Hello World!");
Only one file in your application may use top-level statements. If the compiler finds top-level statements in multiple source files, it’s an error. It’s also an error if you combine top-level statements with a declared program entry point method, typically a Main
method. In a sense, you can think that one file contains the statements that would normally be in the Main
method of a Program
class.
One of the most common uses for this feature is creating teaching materials. Beginner C# developers can write the canonical “Hello World!” in one or two lines of code. None of the extra ceremony is needed. However, seasoned developers will find many uses for this feature as well. Top-level statements enable a script-like experience for experimentation similar to what Jupyter notebooks provide. Top-level statements are great for small console programs and utilities. Azure Functions are an ideal use case for top-level statements.
Most importantly, top-level statements don't limit your application’s scope or complexity. Those statements can access or use any .NET class. They also don’t limit your use of command-line arguments or return values. Top-level statements can access an array of strings named args. If the top-level statements return an integer value, that value becomes the integer return code from a synthesized Main
method. The top-level statements may contain async expressions. In that case, the synthesized entry point returns a Task
, or Task<int>
.