为啥将“switch”类型参数的值传递给字符串参数?

Posted

技术标签:

【中文标题】为啥将“switch”类型参数的值传递给字符串参数?【英文标题】:Why is the value of "switch" type parameter passed to a string parameter?为什么将“switch”类型参数的值传递给字符串参数? 【发布时间】:2018-01-23 07:36:21 【问题描述】:

测试代码(test.ps1):

Param(
    [string]$content = $null,
    [switch]$flag = $false
)
Write-Host $content

输出:

PS C:\Users\powershell> .\test.ps1 PS C:\Users\powershell> .\test.ps1 -flag $true 真的 PS C:\Users\powershell> .\test.ps1 -flag $false 错误的 PS C:\Users\powershell> .\test.ps1 -flag $true -content "lalala" 拉拉拉

无论我将$content设置为$null,还是"",或者没有任何默认值,输出都是一样的。

那么为什么$content 会从$flag 中取值呢?

【问题讨论】:

你没有向-flag传递任何值。 开关参数,在它们的一般用法中,如果你不在命令行中指定它们,则为 $false,如果你在命令行中指定它们,则为 $true。 @PetSerAl 我无法重现此问题,您使用的是什么 psversion?什么操作系统? 我认为这里真正的混淆点是 $true 被解析器解释为位置参数并隐式绑定到 -Content 【参考方案1】:

@PetSerAl已经指出你的误解是什么,但可能有点太简短了,所以我再详细说明一下。

[switch] 参数不像常规参数那样采用值。您通常通过提供或省略参数将其分别设置为 true 或 false:

PS C:\> 获取内容 .\test.ps1 参数( [字符串]$Content = $null, [开关]$标志 ) $flag.IsPresent $内容 PS C:\> .\test.ps1 错误的 PS C:\> .\test.ps1 -Flag 真的

或者,您可以通过在开关参数和值之间放置冒号来显式传递值:

PS C:\> .\test.ps1 -Flag:$false 错误的 PS C:\> .\test.ps1 -Flag:$true 真的

允许冒号后面的空格,但前面不允许(-Flag: $false$false 作为开关值传递,-Flag :$false 则不允许)。

如果您尝试分配开关值 没有冒号,则该值实际上传递给行中的下一个参数,在您的情况下为 -Content 参数:

PS C:\> .\test.ps1 -Flag $false True #参数$Flag的值 False # (位置)参数 $Content 的值 PS C:\> .\test.ps1 -Flag -Content $false True #参数$Flag的值 False # (命名的)参数 $Content 的值

如果您使用-Flag $true(不带冒号)并且将值传递给(命名的)参数-Content,则值$true作为未命名的第三个参数传递(可通过automatic variable$args),就像你把值放在语句的末尾一样:

PS C:\> 获取内容 .\test2.ps1 参数( [字符串]$Content = $null, [开关]$标志 ) $flag.IsPresent $内容 $args[0] PS C:\> .\test2.ps1 -Flag $false -Content 'something' 真的 某物 False # $false 作为未命名的第三个参数传递 PS C:\> .\test2.ps1 -Flag:$false -Content 'something' False # $false 作为开关参数 $Flag 的显式值传递 某物 PS C:\> .\test2.ps1 -Flag -Content 'something' $false 真的 某物 False # $false 作为未命名的第三个参数传递

【讨论】:

冒号后面可以有空格。【参考方案2】:

运行这个测试代码,像在问题中那样调用它。添加这个测试:

C:\Users\powershell> .\test.ps1 -flag

脚本将说明以下几点:

根据 4c74356b41 的注释,除非在命令行中指定,否则开关为 $false。所以-flag$flag 开关设置为true; -flag $true 将标志设置为真并且将参数$true 传递给内容。 由此,无需在脚本参数中指定$flag=$false 添加了一个测试,以便您可以看到$content 何时为空/null,因为也不需要$content=$null
param(
    [string]$content,
    [switch]$flag
)

$test = [string]::IsNullOrEmpty($content)

Write-Output "content: $content"
Write-Output "flag   : $flag"
Write-Output "Is content null: $test"

【讨论】:

【参考方案3】:

我将补充一点,您也可以通过 splatting 分配值,通过 splat 参数分配将值从 $true 更改为 $false 将改变您的开关“检测”。当您使用另一个值或属性来确定是否应该使用开关时,这很有用。

function FooBar 
    param (
        [switch]
        $Foo
    )
    if ($Foo)
        "Foo"
    
    else
        "Bar"
    

$splat = @
    Foo = $False

FooBar @splat

【讨论】:

以上是关于为啥将“switch”类型参数的值传递给字符串参数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们将字符串数组作为参数传递给 main() 方法,为啥不传递任何集合类型或包装类型或原始类型?

为啥将字符串文字传递给 char* 参数有时只是编译器错误?

如何通过 FromQuery 参数将“System.Object”类型传递给控制器

以下Java代码执行结果是啥,请详细分析为啥?

当需要一个形式参数直接改变对应实参的值时,该形式参数应说明为啥参数?

值传递和引用传递(不是引用类型的传递)的区别