什么情况下生成的Top Level Statement类会是$Program?

gun*_*171 7 c# c#-9.0 toplevel-statement

我一直假设顶级语句生成的类是一个隐藏的、不可访问的类。例如:

System.Console.WriteLine(2);

partial class Program
{
    public static string abc = "def";
}
Run Code Online (Sandbox Code Playgroud)

当使用默认分支“C# 9:顶级语句(2020 年 5 月 27 日)”分支在 SharpLab.io 中运行时,生成的 C# 将是

// [ ... using and assembly attributes ... ]
internal static class $Program
{
    private static void $Main(string[] args)
    {
        Console.WriteLine(2);
    }
}
internal class Program
{
    public static string abc = "def";
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,默认分支发出<Program>$not$Program<Main>$not $Main

但是,众所周知,您可以使用partialProgram来增强生成的类。修改代码以打印该字段...

System.Console.WriteLine(abc);
partial class Program { public static string abc = "def"; }
Run Code Online (Sandbox Code Playgroud)

...并使用某些特定的较新分支“C# Next:文件类型(2022 年 7 月 5 日)”再次运行将生成组合类:

// [ ... using and assembly attributes ... ]
internal class Program
{
    public static string abc = "def";

    private static void <Main>$(string[] args)
    {
        Console.WriteLine(abc);
    }
}
Run Code Online (Sandbox Code Playgroud)

根据记录,我不知道此分支使用什么 C# 编译器版本,我假设是 C# 10 的某个版本。

但是,默认分支“C# 9:顶级语句(2020 年 5 月 27 日)”分支将产生语法错误,abc无法找到该字段。

我在 Sharplab 之外重现此问题时遇到问题。创建 .NET 5 / C# 9(此功能出现的版本)控制台应用程序在本地编译并运行:

System.Console.WriteLine(2);

partial class Program
{
    public static string abc = "def";
}
Run Code Online (Sandbox Code Playgroud)
System.Console.WriteLine(abc);
partial class Program { public static string abc = "def"; }
// I have SDK 5.0.408 and runtime 5.0.14,15,17 installed, along with others for core 3.1 and .NET 6
Run Code Online (Sandbox Code Playgroud)

Dotnet fiddle也会编译代码,但它只允许我选择.NET 6,C#版本未知。

假设这不是 Sharplabs 的错误,我的假设是发出的类针对不同的 C# 9 编译器发生了变化。Sharplabs 可能会显示原始的C# 9 编译器,但我的计算机可能正在运行较新的版本。

我能看到的唯一其他证据是dotnet/csharplang git 存储库中的编辑,它将记录的发出类从 更改static class $Programpartial class Program。尽管此文件位于“proposal”文件夹中,但它似乎与发布到 Microsoft 文档中的文件相同,因此在过去的某个时刻,记录了该类名称为$Program.

为什么 Sharplab 将第一个代码块编译为两个类,为什么它不能接受部分类来扩充入口点类?这个功能发布后有修改吗?

Gur*_*ron 2

这现在反映在顶级语句功能规范中:

该类型被命名为“Program”,因此可以通过源代码中的名称进行引用。它是一个部分类型,因此源代码中名为“Program”的类型也必须声明为部分类型。

通过2022 年 6 月 22 日的提交对之前的内容进行了更改:

请注意,名称“Program”和“Main”仅用于说明目的,编译器使用的实际名称取决于实现,并且类型和方法都不能通过源代码中的名称引用

我的猜测是,所做的更改是为了支持ASP.NET Core与 .NET 6 中新托管模型的集成测试,并且首次提及这种可能性的日期是2021 年 10 月 21 日

简而言之,任何现代 .NET 6+ 编译器都应该生成Program类,对于早期版本,您不应该依赖命名(尽管 .NET 5 现在已经 EOL,这不是很相关)。