This is the first in a series of articles on new features introduced in C#9.
Top-level statements allow you to simplify and remove some of the “ceremony” in your code.
For example, take the following console application written in C#8:
using System.Linq;
using static System.Console;
namespace ConsoleAppCS8
{
class Program
{
static int Main(string[] args)
{
string greeting = "";
if (args.Any())
{
greeting = args[0];
}
WriteLine("Please enter your name");
var name = ReadLine();
var upperName = ConvertToUpper(name);
WriteLine($"{greeting} {upperName}");
return 42;
}
public static object ConvertToUpper(string name)
{
return name.ToUpperInvariant();
}
}
}
In the preceding code the “ceremony” consists of things such as the enclosing namespace, the Program class outline, and the Main method itself.
With top-level statements in C# 9 this code can be simplified to the following:
using System.Linq;
using static System.Console;
string greeting = "";
if (args.Any())
{
greeting = args[0];
}
WriteLine("Please enter your name");
var name = ReadLine();
var upperName = ConvertToUpper(name);
WriteLine($"{greeting} {upperName}");
return 42;
static object ConvertToUpper(string name)
{
return name.ToUpperInvariant();
}
Notice in the C# 9 version that the structure is a lot “flatter” because there are no nested {} from the namespace, class, and Main method.
The application will still act in the same way, there is just less boilerplate code.
Notice that in the top-level version you can still have methods e.g. ConvertToUpper(), you can still return a value return 42; and you can still access any command line arguments greeting = args[0];
Some Considerations
Whilst top-level statement make the application seem more “script like” this may or may not be a good thing from someone learning C# for the very first time, depending on if they have any other prior programming experience.
Behind the scenes, a synthesized entry point into the application is created for you. If you return a value, the synthesized entry point (a bit like the Main method in the C# 8 version) will have a return value and if you use any async code the synthesized entry point will return Task or Task<int> – essentially using top-level statements doesn’t restrict you from the kind of code you can write.
Notice in the C# 8 version the method public static object ConvertToUpper(string name) could be accessed by another class in the console app:
class Class1
{
public void XYZ()
{
Program.ConvertToUpper("ddd");
}
}
In the C# 9 top-level version the method becomes:
static object ConvertToUpper(string name)
{
return name.ToUpperInvariant();
}
If we try to write the same Class1 in the C# 9 project we’ll get an error “Error CS0103 The name 'Program' does not exist in the current context “. We could of course refactor the ConvertToUpper() method into an explicit static class to make it accessible
You can only have one top-level file in a project, and you can’t also have an explicit Main method entry point at the same time without getting a compiler warning.
A file with top level statements can also include namespaces/classes but they must be after the top-level statements.
If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.
SHARE: