Main() 和命令列引數

Main 方法是 C# 應用程式的進入點。 (程式庫和服務不需要使用 Main 方法做為進入點)。啟動應用程式時,Main 方法是第一個叫用的方法。

C# 程式中只能有一個進入點。 如果您具有多個含 Main 方法的類別,就必須使用 StartupObject 編譯器選項來編譯您的程式,以指定要使用哪一個 Main 方法做為進入點。 如需詳細資訊,請參閱 StartupObject (C# 編譯器選項)

class TestClass
{
    static void Main(string[] args)
    {
        // Display the number of command line arguments.
        Console.WriteLine(args.Length);
    }
}

您也可以在一個檔案中使用最上層語句作為應用程式的進入點。 如同 Main 方法,最上層語句也可以 傳回值 並存取 命令行自變數。 如需詳細資訊,請參閱 最上層語句

using System.Text;

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

// Display the command line arguments using the args variable.
foreach (var arg in args)
{
    builder.AppendLine($"Argument={arg}");
}

Console.WriteLine(builder.ToString());

// Return a success code.
return 0;

概觀

  • Main 方法是可執行程式的進入點;它是程式控制開始和結束的位置。
  • Main 會宣告於類別或結構內部。 Main 必須是 static,而且不需要是 public。 (在先前的範例中,它會接收的預設存取 private權。)封入 class 可以是 static
  • Main 可以具有 voidintTaskTask<int> 傳回型別。
  • 只有當 Main 傳回 TaskTask<int> 時,Main 的宣告才可以包含 async 修飾詞。 這特別排除 async void Main 方法。
  • Main 方法不一定要使用包含命令列引數的 string[] 參數來宣告。 使用 Visual Studio 來建立 Windows 應用程式時,您可以手動新增參數,或使用 GetCommandLineArgs() 方法來取得命令列引數。 參數會讀入來做為以零為基礎的命令列引數。 不同於 C 和 C++,程式的名稱不會被視為 args 陣列中的第一個命令列引數,但這是 GetCommandLineArgs() 方法的第一個元素。

下列清單顯示有效 Main 特徵標記:

public static void Main() { }
public static int Main() { }
public static void Main(string[] args) { }
public static int Main(string[] args) { }
public static async Task Main() { }
public static async Task<int> Main() { }
public static async Task Main(string[] args) { }
public static async Task<int> Main(string[] args) { }

上述範例全都使用 public 存取子修飾詞。 這很典型,但並非必要。

當主控台應用程式必須啟動且等待 Main 中的 await 非同步作業時,新增的 asyncTaskTask<int> 傳回型別可簡化程式碼。

Main() 傳回值

您可以使用下列其中一種方式,透過定義方法從 Main 方法傳回 int

Main 方法程式碼 Main 特徵標記
不使用 argsawait static int Main()
使用 args,不使用 await static int Main(string[] args)
不使用 args,使用 await static async Task<int> Main()
使用 argsawait static async Task<int> Main(string[] args)

如果未使用來自 Main 的傳回值,則傳回 voidTask 可允許使用比較簡單的程式碼。

Main 方法程式碼 Main 特徵標記
不使用 argsawait static void Main()
使用 args,不使用 await static void Main(string[] args)
不使用 args,使用 await static async Task Main()
使用 argsawait static async Task Main(string[] args)

不過,若是傳回 intTask<int>,可讓程式將狀態資訊傳達給其他會叫用可執行檔的程式或指令碼。

下列範例示範如何存取流程的結束程式碼。

此範例使用 .NET Core 命令列工具。 如果您不熟悉 .NET Core 命令列工具,您可以在此開始使用文章中了解這些工具。

執行 dotnet new console 來建立新的應用程式。 修改 Program.cs 中的 Main 方法,如下所示:

// Save this program as MainReturnValTest.cs.
class MainReturnValTest
{
    static int Main()
    {
        //...
        return 0;
    }
}

在 Windows 中執行程式時,任何從 Main 函式傳回的值,皆會儲存在環境變數中。 您可以從批次檔使用 ERRORLEVEL 或從 PowerShell 使用 $LastExitCode 來擷取此環境變數。

您可以使用 dotnet CLIdotnet build 命令來建置應用程式。

接下來,建立 PowerShell 指令碼以執行此應用程式,並顯示結果。 將下列程式碼貼入文字檔,將它儲存為 test.ps1,並放到包含專案的資料夾中。 在 PowerShell 命令提示字元中鍵入 test.ps1,以執行 PowerShell 指令碼。

由於程式碼會傳回零,因為批次檔會報告成功。 不過,如果您將 MainReturnValTest.cs 變更為傳回非零值,並重新編譯程式,則 PowerShell 指令碼的後續執行會報告失敗。

dotnet run
if ($LastExitCode -eq 0) {
    Write-Host "Execution succeeded"
} else
{
    Write-Host "Execution Failed"
}
Write-Host "Return value = " $LastExitCode
Execution succeeded
Return value = 0

Async Main 傳回值

您宣告 Mainasync 傳回值時,編譯器會產生在 Main 中呼叫非同步方法的重複使用程式碼。 如果您未指定 async 關鍵字,則必須自行撰寫該程式碼,如下列範例所示。 此範例中的程式碼可確保程式在非同步作業完成之前執行:

class AsyncMainReturnValTest
{
    public static void Main()
    {
        AsyncConsoleWork().GetAwaiter().GetResult();
    }

    private static async Task<int> AsyncConsoleWork()
    {
        // Main body here
        return 0;
    }
}

此重複使用程式碼可取代為:

class Program
{
    static async Task<int> Main(string[] args)
    {
        return await AsyncConsoleWork();
    }

    private static async Task<int> AsyncConsoleWork()
    {
        // main body here 
        return 0;
    }
}

宣告 Main 成為 async 的優點是編譯器一律會產生正確的程式碼。

當應用程式進入點傳回 TaskTask<int> 時,編譯器會產生新的進入點,以呼叫應用程式程式碼中宣告的進入點方法。 假設此進入點稱為 $GeneratedMain,編譯器會為這些進入點產生下列程式碼:

  • static Task Main() 會導致編譯器發出 private static void $GeneratedMain() => Main().GetAwaiter().GetResult(); 的對等項目
  • static Task Main(string[]) 會導致編譯器發出 private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult(); 的對等項目
  • static Task<int> Main() 會導致編譯器發出 private static int $GeneratedMain() => Main().GetAwaiter().GetResult(); 的對等項目
  • static Task<int> Main(string[]) 會導致編譯器發出 private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult(); 的對等項目

注意

如果這些範例在 Main 方法上使用 async 修飾詞,編譯器會產生相同的程式碼。

命令列引數

您可以使用下列其中一種方式,透過定義方法以將引數傳送給 Main 方法:

Main 方法程式碼 Main 特徵標記
沒有傳回值,不使用 await static void Main(string[] args)
傳回值,不使用 await static int Main(string[] args)
沒有傳回值,使用 await static async Task Main(string[] args)
傳回值,使用 await static async Task<int> Main(string[] args)

如果未使用引數,您可以對於稍微簡單的程式碼從方法特徵標記中省略 args

Main 方法程式碼 Main 特徵標記
沒有傳回值,不使用 await static void Main()
傳回值,不使用 await static int Main()
沒有傳回值,使用 await static async Task Main()
傳回值,使用 await static async Task<int> Main()

注意

您也可以使用 Environment.CommandLineEnvironment.GetCommandLineArgs,以從主控台或 Windows Forms 應用程式的任何點存取命令列引數。 若要在 Windows Forms 應用程式的 Main 方法特徵標記中啟用命令列引數,您必須手動修改 Main 的特徵標記。 Windows Forms 設計工具所產生的程式碼會建立沒有輸入參數的 Main

Main 方法的參數是代表命令列引數的 String 陣列。 您通常會透過測試 Length 屬性來決定引數是否存在,例如:

if (args.Length == 0)
{
    System.Console.WriteLine("Please enter a numeric argument.");
    return 1;
}

提示

args 陣列不可為 Null。 因此,在沒有 Null 檢查的情況下存取 Length 屬性是安全的。

您也可以使用 Convert 類別或 Parse 方法,將字串引數轉換為數字類型。 例如,下列陳述式將使用 Parse 方法,以將 string 轉換為 long 數字:

long num = Int64.Parse(args[0]);

也可能使用別名為 Int64 的 C# 類型 long

long num = long.Parse(args[0]);

您還可以使用 Convert 類別方法 ToInt64 執行相同作業:

long num = Convert.ToInt64(s);

如需詳細資訊,請參閱 ParseConvert

提示

剖析命令行自變數可能相當複雜。 請考慮使用 System.CommandLine 連結庫(目前為 Beta 版)來簡化程式。

下列範例示範如何在主控台應用程式中使用命令列引數。 應用程式會在執行階段接受一個引數,並將引數轉換為整數,以及計算數字的階乘。 如果未提供任何引數,則應用程式會發出說明程式正確用法的訊息。

若要從命令提示字元編譯和執行應用程式,請遵循下列步驟︰

  1. 將下列程式碼貼入任何文字編輯器,然後將檔案儲存為名稱為 Factorial.cs 的文字檔案。

    public class Functions
    {
        public static long Factorial(int n)
        {
            // Test for invalid input.
            if ((n < 0) || (n > 20))
            {
                return -1;
            }
    
            // Calculate the factorial iteratively rather than recursively.
            long tempResult = 1;
            for (int i = 1; i <= n; i++)
            {
                tempResult *= i;
            }
            return tempResult;
        }
    }
    
    class MainClass
    {
        static int Main(string[] args)
        {
            // Test if input arguments were supplied.
            if (args.Length == 0)
            {
                Console.WriteLine("Please enter a numeric argument.");
                Console.WriteLine("Usage: Factorial <num>");
                return 1;
            }
    
            // Try to convert the input arguments to numbers. This will throw
            // an exception if the argument is not a number.
            // num = int.Parse(args[0]);
            int num;
            bool test = int.TryParse(args[0], out num);
            if (!test)
            {
                Console.WriteLine("Please enter a numeric argument.");
                Console.WriteLine("Usage: Factorial <num>");
                return 1;
            }
    
            // Calculate factorial.
            long result = Functions.Factorial(num);
    
            // Print result.
            if (result == -1)
                Console.WriteLine("Input must be >= 0 and <= 20.");
            else
                Console.WriteLine($"The Factorial of {num} is {result}.");
    
            return 0;
        }
    }
    // If 3 is entered on command line, the
    // output reads: The factorial of 3 is 6.
    
  2. 從 [開始] 畫面或 [開始] 功能表中,開啟 Visual Studio [開發人員命令提示字元] 視窗,然後瀏覽至剛剛建立的檔案包含在內的資料夾。

  3. 輸入下列命令以編譯應用程式。

    dotnet build

    如果您的應用程式沒有任何編譯錯誤,則會建立名為 Factorial.exe 的可執行檔。

  4. 輸入下列命令以計算 3 的階乘:

    dotnet run -- 3

  5. 命令會產生以下輸出:The factorial of 3 is 6.

注意

在 Visual Studio 中執行應用程式時,您可以在專案設計工具、偵錯頁中指定命令列引數。

C# 語言規格

如需詳細資訊,請參閱<C# 語言規格>。 語言規格是 C# 語法及用法的限定來源。

另請參閱