Main() 与命令行参数 很多现有代码库仍使用显式Main​ 方法作为入口点。这篇把Main​ 的所有有效签名、返回值规则、命令行参数处理以及异步Main的用法完整梳理一遍。Main 的声明规则必须 static、8 种有效签名的完整清单返回值与退出码int​ 和Taskint如何向调用方传递状态命令行参数string[] args​ 的使用方式与GetCommandLineArgs()的区别异步 Mainasync Task Main的规则和陷阱一、Main 方法的基本规则​Main​ 是 C# 程序的入口点。程序启动时运行时先调用Main​Main返回后程序结束。规则说明声明位置必须在class​或struct​内封闭类可以是static修饰符必须static访问级别任意访问修饰符均可默认private返回类型​void​、int​、Task​或Taskint参数可选string[] args唯一入口点一个程序只能有一个入口点多Main​时需用-main编译器选项指定二、所有有效的 Main 签名// 无参数、无异步、无返回码staticvoidMain(){}staticintMain(){}​// 带命令行参数staticvoidMain(string[]args){}staticintMain(string[]args){}​// 异步staticasyncTaskMain(){}staticasyncTaskintMain(){}​// 异步 命令行参数staticasyncTaskMain(string[]args){}staticasyncTaskintMain(string[]args){}完整功能矩阵Main 声明​string[] args​await退出码​static void Main()❌❌❌​static int Main()❌❌✅​static void Main(string[] args)✅❌❌​static int Main(string[] args)✅❌✅​static async Task Main()❌✅❌​static async Taskint Main()❌✅✅​static async Task Main(string[] args)✅✅❌​static async Taskint Main(string[] args)✅✅✅选择策略不需要args​ → 省略string[] args参数不需要退出码 → 用void​ 或Task需要await​ → 用async Task​ 或async Taskint全都要 →static async Taskint Main(string[] args)关键点async void Main​ 是非法的。异步Main​ 必须返回Task​ 或Taskint​因为运行时需要等待Task完成后才结束进程。三、返回值与退出状态码返回int​ 或Taskint时程序可以向调用方其他程序或脚本传递状态信息classMainReturnValTest{staticintMain(){// ... 业务逻辑 ...return0;// 0 成功非零 错误}}约定​return 0表示成功​return 非零值表示错误具体值由程序自定义如何获取退出码环境方式PowerShell​$LastExitCodeCMD / 批处理​%ERRORLEVEL%Linux / macOS Shell​$?异步 Main 的返回值classProgram{staticasyncTaskintMain(string[]args){returnawaitAsyncConsoleWork();}​privatestaticasyncTaskintAsyncConsoleWork(){// 异步工作...return0;}}代码解析​​async Taskint Main​​运行时调用Main​ 后等待返回的​Task​​完成才结束进程不能返回​async void​​或​async int​​async​ 修饰符要求返回类型是可等待的Task​ 或Taskint​void​ 和int不是​​return await ...​把异步工作的结果作为进程退出码返回四、命令行参数4.1 基本用法staticvoidMain(string[]args){Console.WriteLine(args.Length);}关键特性​args​ 是string[]​永不为​null​未提供参数时args.Length 0空数组参数是零索引的args[0]是第一个参数4.2 与 C/C 的区别特性C#C/C​args[0]第一个命令行参数程序名称获取程序名​Environment.GetCommandLineArgs()[0]​argv[0]常见坑从 C/C 转过来的开发者容易以为args[0]​ 是程序名实际不是。用Environment.GetCommandLineArgs()[0]​ 或Process.GetCurrentProcess().MainModule.FileName获取。4.3 参数类型转换longnumlong.Parse(args[0]);intcountint.Parse(args[1]);doublepricedouble.Parse(args[2]);建议手动Parse​ 适合简单场景。复杂的命令行参数如--name value --verbose​考虑使用System.CommandLine库。4.4 完整示例classTestClass{staticvoidMain(string[]args){// 显示参数数量Console.WriteLine($参数数量:{args.Length});​// 遍历参数for(inti0;iargs.Length;i){Console.WriteLine($args[{i}] {args[i]});}​// 用 GetCommandLineArgs 获取完整命令行含程序名string[]allArgsEnvironment.GetCommandLineArgs();Console.WriteLine($程序名:{allArgs[0]});}}五、顶级语句 vs 显式 Main 对照需求顶级语句写法显式 Main 写法打印 args 数量​Console.WriteLine(args.Length);​static void Main(string[] args) { Console.WriteLine(args.Length); }异步​await Task.Delay(1000);​static async Task Main() { await Task.Delay(1000); }返回退出码​return 0;​static int Main() { return 0; }异步 退出码​await ...; return 0;​static async Taskint Main() { await ...; return 0; }最后如果从零开始建新项目直接上顶级语句会更简洁。但如果你在维护一个使用显式Main​ 的旧项目或者需要精确控制入口点的多Main​ 选择-main​ 编译器选项这篇就是你的完整参考。记住三条async void Main​ 非法、args永不为 null、退出码 0 表示成功。‍