Powershell 将null传递给函数的强制参数

Powershell 将null传递给函数的强制参数,powershell,Powershell,实际上,我的问题归结为: 我不能使用带有强制参数的函数并将$null传递给该参数: Function Foo { Param ( [Parameter(Mandatory = $true)][string] $Bar ) Write-Host $Bar } Foo -Bar $null 这将返回foo:无法将参数绑定到参数“Bar”,因为它是空字符串。 同样,将其设置为阵列也会失败: Function Foo { Param

实际上,我的问题归结为:

我不能使用带有强制参数的函数并将$null传递给该参数:

Function Foo
{
    Param
    (
        [Parameter(Mandatory = $true)][string] $Bar
    )

    Write-Host $Bar
}

Foo -Bar $null
这将返回
foo:无法将参数绑定到参数“Bar”,因为它是空字符串。

同样,将其设置为阵列也会失败:

Function Foo
{
    Param
    (
        [Parameter(Mandatory = $true)][string[]] $Bar
    )

    Write-Host $Bar
}

Foo -Bar 1, 2 

> 1 2

Foo -Bar 1, 2, $null

> foo : Cannot bind argument to parameter 'Bar' because it is an empty string.
在编程术语中,完全可能有一个函数接受一个强制的可为null的参数,但我在PowerShell中找不到这样做的方法

我该怎么做呢?

我想你错过了分离参数的步骤

Param (
    [string]$ObjectName,
    [int]$ObjectId,
    [wmi]$Object
)

您应该能够使用[string]参数的[AllowEmptyString()]参数属性和/或其他类型的[AllowNull()]参数属性。我已将[AllowEmptyString()]属性添加到您示例中的函数中:

Function Foo {
    Param
    (
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]  <#-- Add this #>
        [string] $Bar
    )

    Write-Host $Bar
}

Foo -Bar $null
函数Foo{
Param
(
[参数(必需=$true)]
[AllowEmptyString()]
[字符串]$Bar
)
写入主机$Bar
}
Foo-Bar$null
有关更多信息,请查看帮助主题

请注意,PowerShell将在强制参数的参数绑定期间强制将$null值转换为某些类型的实例,例如,
[string]$null
变为空字符串,
[int]$null
变为0。要解决这个问题,您有几个选择:

  • 删除参数类型约束。您可以在代码中检查$null,然后转换为所需的类型
  • 使用System.Nullable(请参阅其他答案)。这仅适用于值类型
  • 重新考虑函数设计,这样您就不会有应该允许null的强制参数

正如Rohn Edwards在回答中提到的,
[AllowNull()]
和/或
[allowmptystring()]
是解决方案的一部分,但有几点需要考虑

尽管问题中给出的示例使用类型字符串,但标题上的问题是如何将null传递给强制参数,而不提及类型,因此我们需要稍微扩展答案

首先让我们看看PowerShell如何处理将$null分配给某些类型的问题:

PS C:\> [int] $null
0
PS C:\> [bool] $null
False
PS C:\> [wmi] $null
PS C:\>
PS C:\> [string] $null

PS C:\>
分析结果:

  • $null
    传递给
    [int]
    将返回值为
    0
  • $null
    传递给
    [bool]
    将返回值为
    False的
    [bool]
    对象
  • $null
    传递给
    [wmi]
    将返回。。。没有什么。它根本不创建对象。这可以通过执行
    ([wmi]$null).GetType()
    来确认,这会引发错误
  • $null
    传递给
    [string]
    将返回值为
    '
    (空字符串)的
    [string]
    对象。这可以通过执行
    ([string]$null).GetType()
    ([string]$null).Length来确认
那么,如果我们有一个带有非强制性
[int]
参数的函数,如果我们不传递该参数,它会有什么值?让我们检查一下:

Function Foo {
    Param (
        [int] $Bar
    )
    Write-Host $Bar
}

Foo
> 0
显然,如果它是一个
[bool]
值,则为
False
,如果它是
[string]
值,则为
'

因此,当我们有一个大多数标准类型的强制参数,并将其赋值为
$null
时,我们得到的不是
$null
,而是该类型的“默认值”

例如:

Function Foo {
    Param (
        [Parameter(Mandatory = $true)][int] $Bar
    )
    Write-Host $Bar
}

Foo -Bar $null
> 0
注意这里根本没有
[AllowNull()]
,但它仍然返回
0

[string]
略有不同,因为它不允许在强制参数上使用空字符串,这就是问题中的示例失败的原因
[AllowNull()]
也无法修复它,因为空字符串与
$null
不同,因此我们需要使用
[AllowEmptyString()]
。其他任何事情都会失败

那么,
[AllowNull()]
在哪里发挥作用,以及如何将“real”
$null
传递给int、bool、wmi等

int和bool都不是可为null的类型,因此为了向它们传递一个“real”
$null
,需要将它们设置为可为null:

Function Foo {
    Param (
        [Parameter(Mandatory = $true)][AllowNull()][System.Nullable[int]] $Bar
    )
    Write-Host $Bar
}
这允许将“true”
$null
传递给int,显然,在调用
Write Host
时,它会将
$null
转换为字符串,这意味着我们再次得到一个
'
,因此它仍然会输出一些内容,但传递的是“true”
$null

[wmi]
(或.NET类)这样的可为空类型更容易,因为它们从一开始就可以为空,所以它们不需要设置为可为空,但仍然需要
[AllowNull()]

至于将
[string]
设为真正的可空值,我仍然无法做到这一点,因为我试图做到:

[System.Nullable[string]]
返回一个错误。很可能是因为
system.string
已经可以为空,尽管PowerShell似乎不这么认为

编辑

我刚才注意到

[bool] $null
被强制为
False
,正在执行

Function Foo {
    Param (
        [bool] $Bar
    )
    $Bar
}

Foo -Bar $null
引发以下错误:

Foo : Cannot process argument transformation on parameter 'Bar'. Cannot convert value "" to type "System.Boolean".

这很奇怪,更奇怪的是,在上面的函数中使用
[switch]
而不是
[bool]
可以工作。

首先,添加
AllowNull
属性:

Function Foo
{
    Param
    (
        [Parameter(Mandatory = $true)][AllowNull()][string] $Bar
    )

    Write-Host $Bar
}
然后,当您调用函数时,请注意当用于
[string]
时,
$null
将成为空字符串,而不是空引用。因此(自PowerShell 3(2012)以来)使用
[NullString]::Value
如下:

Foo -Bar ([NullString]::Value)


编辑:从调用站点上看,这似乎有效,但当您到达函数中的
Write Host
cmdlet时,
$Bar
将再次变为空字符串。见下面的评论。我们必须得出结论,PowerShell坚持字符串必须是这样的。请注意,
NullString
(在其他情况下对我很有用)在其文档中只承诺在p