.NET 命令行参数包含应用程序路径吗?

.NET 命令行参数包含应用程序路径吗?

发布于 2018-09-11 13:28 更新于 2018-09-13 03:24

如果你关注过命令行参数,也许发现有时你会在命令行参数的第一个参数中中看到应用程序的路径,有时又不会。那么什么情况下有路径呢?


其实是否有路径只是取决于获取命令行参数的时候用的是什么方法。而这是 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 函数中的命令行参数

这种行为与具体的 .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 中的命令行参数

事实上这样的差异不止在 .NET 中有体现,整个 Windows 上的程序都是这样的特性。这在《Windows 核心编程》一书中是有说明的。

总结

  1. Main 函数的参数中不包含应用程序执行路径;
  2. System.Environment.GetCommandLineArgs() 得到的命令行参数中包含应用程序的执行路径;
  3. Windows 上的所有程序其命令行参数的行为表现都是如此,这不是 .NET 的专属特性。

本文会经常更新,请阅读原文: https://walterlv.com/post/when-will-the-command-line-args-contain-the-executable-path.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Spark学习技巧

kafka源码系列之mysql数据增量同步到kafka

一,架构介绍 生产中由于历史原因web后端,mysql集群,kafka集群(或者其它消息队列)会存在一下三种结构。 1,数据先入mysql集群,再入kafka ...

1.6K70
来自专栏大内老A

ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline - Part II

二、ASP.NET Runtime Pipeline(续ASP.NET Http Runtime Pipeline - Part I) 现在我们真正进入ASP....

21780
来自专栏木宛城主

ASP.NET那点不为人知的事(一)

我们上网时,在浏览器地址输入网址,按下回车,一张网页就呈现在我们眼前。这究竟发生了什么?对于一名优秀的Programmer来说,我想有必要一下熟悉浏览器---...

40680
来自专栏技术小讲堂

State模式的经典应用场景:订单处理(c#实现)场景描述遇到问题解决问题走起

State模式在对象内部状态发生变化的时候,改变自身的行为,这通常是通过切换内部状态对象实现的,对象将自身在各个状态的行为推给了状态对象,从而解开了行为与对象的...

29740
来自专栏大内老A

如何解决分布式系统中的跨时区问题[原理篇]

《谈谈你最熟悉的System.DateTime[上篇][下篇]》从跨时区的角度对DateTime这个我们熟知的类型进行了深入探讨,它们都是为这篇文章作的准备工作...

20370
来自专栏程序员与猫

使用HttpClient的优解

新工作入职不久,目前仍然还在适应环境当中,笔者不得不说看别人的源码实在是令人痛苦。所幸前些日子终于将工作流畅地看了一遍,接下来就是熟悉框架技术的阶段了。 也正是...

48980
来自专栏圣杰的专栏

ABP入门系列(2)——领域层创建实体

这一节我们主要和领域层打交道。首先我们要对ABP的体系结构以及从模板创建的解决方案进行一一对应。网上有代码生成器去简化我们这一步的任务,但是不建议初学者去使用。...

26180
来自专栏大内老A

事件(Event),绝大多数内存泄漏(Memory Leak)的元凶[上篇]

最近这两天一直在忙着为一个项目检查内存泄漏(Memory Leak)的问题,对相关的知识进行了一下简单的学习和探索,其间也有了一些粗浅的经验积累,今天特意写一篇...

25860
来自专栏施炯的IoT开发专栏

windows mobile窗口之间传递数据的方法

    在windows mobile上设计UI的时候,经常会碰到多个窗口的情况。有时候,我们需要将一个窗口中的用户输入信息反应到另一个窗口中去,这就涉及到窗口...

20790
来自专栏张善友的专栏

自定义Unity对象生命周期管理集成ADO.NET Entity Framework

在Unity中,从Unity 取得的实例为 Transient。如果你希望使用多线程方式,就需要在组成时使用lifecycle参数,这时候取出的组件就不再是同一...

37680

扫码关注云+社区

领取腾讯云代金券