1. 程式人生 > >.NET 命令列引數包含應用程式路徑嗎?

.NET 命令列引數包含應用程式路徑嗎?

如果你關注過命令列引數,也許發現有時你會在命令列引數的第一個引數中中看到應用程式的路徑,有時又不會。那麼什麼情況下有路徑呢?

其實是否有路徑只是取決於獲取命令列引數的時候用的是什麼方法。而這是 Windows 作業系統的機制,與具體的執行環境無關。

本文內容

測試程式

考慮下面這樣的測試程式:

using System;
using System.Globalization;

namespace Walterlv.Demo.CommandLines
{
    class Program
    {
        static void Main(string[] args)
{ Console.WriteLine($"引數總數:{args.Length}"); OutputArgsInfo(args); Console.WriteLine($"按任意鍵繼續……"); Console.ReadKey(); } private static void OutputArgsInfo(string[] args) { var digitCount = (args.Length - 1)
.ToString(CultureInfo.InvariantCulture).Length; for (var i = 0; i < args.Length; i++) { Console.WriteLine($"[{i.ToString().PadLeft(digitCount, ' ')}] {args[i]}"); } } } }

當我們向命令列中傳入引數的時候,我們可以得到所有的命令列。

Main 函式中的命令列引數 ▲ Main 函式中的命令列引數

這種行為與具體的 .NET SDK 無關。看我們的專案檔案,可以發現,無論是老舊的 .NET Framework 4.5 還是新的 .NET Framework 4.7.2 還是更加主流的 .NET Core 2.1,命令列引數中都是沒有應用程式路徑的。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>net45;net472;netcoreapp2.1</TargetFrameworks>
  </PropertyGroup>

</Project>

那為什麼有時候會看到應用程式路徑呢?

解釋

在《Windows 核心程式設計》一書中有說到:

可以獲得一個指向程序的完整命令列的指標,方法是呼叫 GetCommandLine 函式:

PTSTR GetCommandLine();

該函式返回一個指向包含完整命令列的快取的指標,該命令列包括執行檔案的完整路徑名。

也就是說,呼叫 GetCommandLine 函式時,我們將得到包含執行檔案的完整路徑名的命令列引數。這個方法對應到 .NET 中,是 System.Environment.GetCommandLineArgs()

於是修改我們剛剛的函式,加上 Environment.GetCommandLineArgs() 的呼叫:

using System;
using System.Globalization;

namespace Walterlv.Demo.CommandLines
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Main 函式引數列表中引數總數:{args.Length}");
            OutputArgsInfo(args);

            args = Environment.GetCommandLineArgs();
            Console.WriteLine($"GetCommandLineArgs 引數總數:{args.Length}");
            OutputArgsInfo(args);

            Console.WriteLine($"按任意鍵繼續……");
            Console.ReadKey();
        }

        private static void OutputArgsInfo(string[] args)
        {
            var digitCount = (args.Length - 1).ToString(CultureInfo.InvariantCulture).Length;

            for (var i = 0; i < args.Length; i++)
            {
                Console.WriteLine($"[{i.ToString().PadLeft(digitCount, ' ')}] {args[i]}");
            }
        }
    }
}

現在,我們能看到引數列表中多了應用程式的完整路徑:

GetCommandLineArgs 中的命令列引數 ▲ GetCommandLineArgs 中的命令列引數

事實上這樣的差異不止在 .NET 中有體現,整個 Windows 上的程式都是這樣的特性。這在《Windows 核心程式設計》一書中是有說明的。

總結

  1. Main 函式的引數中不包含應用程式執行路徑;
  2. System.Environment.GetCommandLineArgs() 得到的命令列引數中包含應用程式的執行路徑;
  3. Windows 上的所有程式其命令列引數的行為表現都是如此,這不是 .NET 的專屬特性。