很多现有代码库仍使用显式Main 方法作为入口点。这篇把Main 的所有有效签名、返回值规则、命令行参数处理以及异步Main的用法完整梳理一遍。Main 的声明规则必须 static、8 种有效签名的完整清单返回值与退出码int 和Taskint如何向调用方传递状态命令行参数string[] args 的使用方式与GetCommandLineArgs()的区别异步 Mainasync Task Main的规则和陷阱一、Main 方法的基本规则Main 是 C# 程序的入口点。程序启动时运行时先调用MainMain返回后程序结束。规则说明声明位置必须在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[] argsawait退出码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 intasync 修饰符要求返回类型是可等待的Task 或Taskintvoid 和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/Cargs[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 表示成功。
Main() 与命令行参数
很多现有代码库仍使用显式Main 方法作为入口点。这篇把Main 的所有有效签名、返回值规则、命令行参数处理以及异步Main的用法完整梳理一遍。Main 的声明规则必须 static、8 种有效签名的完整清单返回值与退出码int 和Taskint如何向调用方传递状态命令行参数string[] args 的使用方式与GetCommandLineArgs()的区别异步 Mainasync Task Main的规则和陷阱一、Main 方法的基本规则Main 是 C# 程序的入口点。程序启动时运行时先调用MainMain返回后程序结束。规则说明声明位置必须在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[] argsawait退出码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 intasync 修饰符要求返回类型是可等待的Task 或Taskintvoid 和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/Cargs[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 表示成功。