Take advantage of the new top-level statements in C# 9.0 to eliminate boilerplate code and make your programs more readable, maintainable, and efficient. Credit: SwissMediaVision / Getty Images When writing programs in the C# programming language, you invariably need to write a lot of boilerplate code — even for simple console applications. Imagine that you want to write some code to test whether a library or an API is functioning properly. You might write a console application to accomplish this, but you’re nonetheless constrained to follow standard C# semantics. You must write your code inside the Main method. Top-level programs, a new concept introduced in C# 9.0, allow you to write code for simple programs sans the need to write boilerplate code. Top-level programs are a great new feature that allows you to write cleaner, shorter, and simpler code. You can take advantage of top-level programs to explore new ideas. This article discusses how you can work with top-level programs in C# 9.0. To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here. Note that C# 9.0 is available in Visual Studio 2019 version 16.9 Preview 1 or later, and in the .NET 5.0 SDK. Create a .NET Core console application project in Visual Studio First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio. Launch the Visual Studio IDE. Click on “Create new project.” In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed. Click Next. In the “Configure your new project” window, specify the name and location for the new project. Click Create. We’ll use this project to work with top-level programs in the subsequent sections of this article. Top-level program example in C# 9.0 Let’s look at a before-and-after example of how top-level programs can eliminate boilerplate code. Before top-level statements in C# 9.0, this is the minimal code you’d write for a console application: using System; namespace IDG_Top_Level_Programs_Demo { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); } } } When working with C# 9.0, we can avoid the noise and take advantage of top-level programs to write our code in a much simpler way. The following code snippet illustrates how you can take advantage of top-level statements to refactor the above code: using System; Console.WriteLine("Hello World!"); In either case, when the program is executed, you’ll see the string “Hello World!” displayed at the console window. Use methods in top-level programs in C# 9.0 You can use methods with top-level programs. Below is a code example that illustrates how you can use methods with top-level programs. System.Console.WriteLine(DisplayMessage("Joydip!")); System.Console.Read(); static string DisplayMessage(string name) { return "Hello, " + name; } When you execute the above program, you should see the output “Hello, Joydip!” appear in the console window: Use classes in top-level programs in C# 9.0 You can also use classes, structs, and enums in top-level programs. The following code snippet illustrates how you can use classes in top-level programs. System.Console.WriteLine(new Author().DisplayMessage("Joydip!")); System.Console.Read(); public class Author { public string DisplayMessage(string name) { return "Hello, " + name; } } When you execute the above program, the output will be similar to Figure 1. How top-level programs work in C# 9.0 So, how do top-level programs work exactly? What happens behind the scenes? Top-level programs are essentially a compiler feature. If you don’t write the boilerplate code, the compiler will generate it for you. Refer to the following piece code we wrote earlier. using System; Console.WriteLine("Hello World!"); The code displayed below (generated using the SharpLab online tool) shows what the compiler-generated code would look like. using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [CompilerGenerated] internal static class <Program>$ { private static void <Main>$(string[] args) { Console.WriteLine("Hello World!"); } } If you look at the compiler-generated code, you’ll see the [CompilerGenerated] attribute on top of the static class generated by the compiler. Top-level programs are a great new feature in C# 9.0, whereby the compiler automatically generates the boilerplate code for you behind the scenes. Top-level programs are great for simple programs that don’t have too many files and dependencies. Note that only one file in your application may use top-level statements; otherwise the compiler throws an error. One downside to top-level programs is that, if you’re new to C#, you might not be able to understand what’s happening in the code behind the scenes. A better way for beginners to learn C# will be using the Main method, and avoiding top-level statements until you understand how the Main method works. But those who have mastered Main will find top-level statements a very useful shortcut. How to do more in C#: How to use pattern matching in C# How to work with read-only collections in C# How to work with static anonymous functions in C# 9 How to work with record types in C# How to use implicit and explicit operators in C# Singleton vs. static classes in C# How to log data to the Windows Event Log in C# How to use ArrayPool and MemoryPool in C# How to use the Buffer class in C# How to use HashSet in C# How to use named and optional parameters in C# How to benchmark C# code using BenchmarkDotNet How to use fluent interfaces and method chaining in C# How to unit test static methods in C# How to refactor God objects in C# Related content how-to How to use FastEndpoints in ASP.NET Core Take advantage of the free open-source FastEndpoints library to build fast and lean APIs in your ASP.NET Core applications. By Joydip Kanjilal Jul 11, 2024 7 mins Microsoft .NET C# Development Libraries and Frameworks how-to How to use Refit to consume APIs in ASP.NET Core Take advantage of Refit REST library to simplify API consumption and make your code cleaner, more efficient, and easier to maintain. By Joydip Kanjilal Jul 04, 2024 10 mins C# Microsoft .NET Software Deployment how-to When to use an abstract class vs. interface in C# Understanding the differences between an abstract class and interface is key to designing loosely coupled and extensible applications. By Joydip Kanjilal Jun 20, 2024 10 mins Small and Medium Business Microsoft .NET C# how-to 6 security best practices for ASP.NET Core Learn the best practices and built-in safeguards for preventing attacks and protecting sensitive data in your ASP.NET Core web applications. By Joydip Kanjilal Jun 07, 2024 6 mins C# Microsoft .NET Web Development Resources Videos