I had thought that using the Top-Level Statements feature in C# 9 essentially wraps your top-level code in the usual Program class and Main method.
A decompiled top-level program looks like this:
[CompilerGenerated]
internal static class $Program
{
private static void $Main(string[] args)
{
// top-level code here
}
}
You can define normal methods at the top-level. They are compiled into the Program class, but outside of the Main method, where extension methods can also be defined.
Because the generated Program class is static and non-generic, I would expect to be able to define extension methods at the top level. However, I get compiler error CS1106: Extension method must be defined in a non-generic static class
Why is this?
The C# Language Specification says:
When the first parameter of a method includes the
thismodifier, that method is said to be an extension method. Extension methods can only be declared in non-generic, non-nested static classes.
According to the language specification, extension methods must be declared in a static class.
It does not matter that top-level methods are implemented by placing them in a hidden static class. Top-level methods are (by definition) not declared in any class, and therefore cannot be extension methods according to the specification.
As with all language design questions, this is the way that it is because this is the way that the language design team designed the language. Presumably the same concerns which prevent you from defining extension methods inside non-static classes also apply to top-level methods.
You can open a discussion in the csharplang repo or ask a question on Gitter if you want someone with more authority to possibly give more detail.
The top-level statement feature is implemented the way you described it: your top level code is wrapped into the compiler generated class and Main method.
Your extension cannot be declared inside this Main method, so your syntax is invalid. An extension declaration is not a top-level statement.
Using SharpLab we can see that, yes, the generated Program is static, and multiple methods declared in a top level context do get compiled correctly (example here), something is missing when comparing to extension methods: The [Extension] attribute, as both the class and method need to be marked with this, official docs here.
This is the code generated by a top level Hello World (some things omited for brevity, full thing here)
[assembly: Extension]
[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");
}
}
Now here's the decompiled code for a class with an extension method:
[Extension]
internal static class Foo
{
[Extension]
private static void WriteToConsole(string source)
{
Console.WriteLine(source);
}
}
Seems like the compiler isn't recognizing that there are extension methods, and as such isn't compiling it correctly. We also can't forcibly place the Extension attribute, as we then get an error saying that
error CS1112: Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'. Use the 'this' keyword instead
And even if we could, we can't place it on the Program class itself
TL;DR: The C# compiler doesn't recognize that there are extension methods in the top level statements, and as such doesn't apply the necessary [Extension] attribute to the class or the method