通过


顶级语句 - 不使用 Main 方法的程序

小窍门

开发软件的新手? 首先开始 学习入门 教程。 这些教程使用顶级语句,因此你已熟悉基础知识。

正在寻找 Main 方法的替代方案? 请参阅主要方法入口点以了解显式Main方法。

对新应用使用 顶级语句 。 通过使用顶级语句,可以直接在文件的根目录中编写可执行代码。

下面是一个 Program.cs 文件,该文件是完整的 C# 程序:

Console.WriteLine("Hello World!");

创建一个新的控制台应用程序时使用 dotnet new console,它默认使用顶级语句。 它们适用于任何大小的程序-从小型实用工具和 Azure Functions 到完整应用程序。 如果有使用显式 Main 方法的现有应用程序,则无需对其进行转换。 这两种样式都编译为等效代码。

以下各节介绍了关于顶级语句可执行与不可执行操作的规则。

入口点规则

一个应用程序只能有一个入口点。 项目只能有一个具有顶级语句的文件,但它可以有任意数量的没有顶级语句的源代码文件。 可以显式编写方法 Main ,但它不能用作入口点。 在具有顶级语句的项目中,即使项目具有一个或多个-main方法,也不能使用Main编译器选项来选择入口点。

编译器会生成一个方法,作为具有顶级语句的项目的程序入口点。 方法的签名取决于顶级语句是包含 await 关键字还是 return 语句。 下表显示了方法签名的外观,使用表中的方法名称 Main 来方便起见。

顶级代码包含 隐式 Main 签名
awaitreturn static async Task<int> Main(string[] args)
await static async Task Main(string[] args)
return static int Main(string[] args)
awaitreturn static void Main(string[] args)

从 C# 14 开始,程序可以是 基于文件的应用,其中单个文件包含该程序。 使用命令运行dotnet <file.cs>,或者直接在 Unix 上使用文件名(例如,./file.cs)。 后者需要在第一行中包含 #!/usr/bin/env dotnet 指令,并设置执行权限(chmod +x <file>)。

using 指令

对于包含顶级语句的单个文件, using 指令必须首先出现在该文件中,如以下示例所示:

using System.Text;

StringBuilder builder = new();
builder.AppendLine("The following arguments are passed:");

foreach (var arg in args)
{
    builder.AppendLine($"Argument={arg}");
}

Console.WriteLine(builder.ToString());

return 0;

命名空间和类型定义

顶级语句隐式位于全局命名空间中。 具有顶级语句的文件还可以包含命名空间和类型定义,但它们必须位于顶级语句之后。 例如:

MyClass.TestMethod();
MyNamespace.MyClass.MyMethod();

public class MyClass
{
    public static void TestMethod()
    {
        Console.WriteLine("Hello World!");
    }
}

namespace MyNamespace
{
    class MyClass
    {
        public static void MyMethod()
        {
            Console.WriteLine("Hello World from MyNamespace.MyClass.MyMethod!");
        }
    }
}

args

顶级语句可以引用 args 变量,以访问在应用启动时传递给应用的任何命令行参数。 变量 args 从不 null,但如果未提供命令行参数,其 Length 为零。 例如:

if (args.Length > 0)
{
    foreach (var arg in args)
    {
        Console.WriteLine($"Argument={arg}");
    }
}
else
{
    Console.WriteLine("No arguments");
}

await 并退出状态码

调用 await 来执行异步方法。 当顶级代码包含 await 时,编译器将生成一个 Task 入口点。 运行时监视Task的完成情况,使进程保持运行中,直到所有异步工作完成。 例如:

Console.Write("Hello ");
await Task.Delay(5000);
Console.WriteLine("World!");

若要在应用程序结束时返回退出代码,请使用 return 该语句。 编译器生成一个入口点,当代码同时包含 Task<int>await 时,该入口点返回 return,或当代码仅包含 int 时返回 return。 例如:

string? s = Console.ReadLine();

int returnValue = int.Parse(s ?? "-1");
return returnValue;