为什么我不能在 C# 9 中定义顶级扩展方法?

Why can't I define top-level extension methods in C# 9?

我曾认为使用 C# 9 中的 Top-Level Statements 功能本质上是将您的顶级代码包装在通常的 Program class 和 Main 方法中。

一个反编译的顶层程序是这样的:

[CompilerGenerated]
internal static class $Program
{
    private static void $Main(string[] args)
    {
        // top-level code here
    }
}

您可以在顶层定义普通方法。它们被编译到 Program class 中,但在 Main 方法之外,其中也可以定义扩展方法。

因为生成的 Program class 是静态的和非泛型的,我希望能够在顶层定义扩展方法。但是,我收到编译器错误 CS1106: Extension method must be defined in a non-generic static class

这是为什么?

顶级语句功能按照您描述的方式实现:您的顶级代码被包装到编译器生成的classMain方法.

无法在此 Main 方法中声明您的扩展,因此您的语法无效。扩展声明不是顶级声明。

使用 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.

这是顶层生成的代码Hello World(为了简洁省略了一些东西,完整的东西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");
    }
}

下面是带有扩展方法的 class 的反编译代码:

[Extension]
internal static class Foo
{
    [Extension]
    private static void WriteToConsole(string source)
    {
        Console.WriteLine(source);
    }
}

似乎编译器没有识别出有扩展方法,因此没有正确编译它。我们也不能强行放置 Extension 属性,因为这样我们会收到一个错误提示

error CS1112: Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'. Use the 'this' keyword instead

即使可以,我们也不能将其放在 Program class 本身上

TL;DR:C# 编译器无法识别顶级语句中的扩展方法,因此不应用必要的 [Extension] 属性到 class 或方法

带着怀疑尝试回答我自己的问题。

我想知道这是否是一种设计选择,顶级方法类似于 C# 7 中的 Local Functions

对于局部函数,方法也被编译到 class 但在方法之外,它们在源代码中定义。生成的方法名看起来也很相似,比如 <$Main>g__Test.

尝试编写与本地函数相同的扩展方法时出现相同的编译器错误:

C# Language Specification 说:

When the first parameter of a method includes the this modifier, that method is said to be an extension method. Extension methods can only be declared in non-generic, non-nested static classes.

根据语言规范,扩展方法必须在静态 class.

声明

将顶级方法实现 放在隐藏的静态class 中并不重要。顶级方法(根据定义)未在 any class 中声明,因此根据规范不能是扩展方法。

与所有语言设计问题一样,这是因为这是语言设计团队设计语言的方式。据推测,阻止您在非静态 classes 中定义扩展方法的同样问题也适用于顶级方法。

如果您希望有更多权限的人提供更多详细信息,您可以在 csharplang repo or ask a question on Gitter 中发起讨论。

根据 Mads Torgersen 在 this video from .NET Conf 2020 中声明为顶级语句的任何函数都是 main() 方法中的局部函数,而不是 Program class 中的方法.

局部函数不能是扩展方法。