将null传递给函数的必需参数

cog*_*el0 18 powershell

从scrath重写的问题使其更具可读性.

实际上我的问题归结为:

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

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

    Write-Host $Bar
}

Foo -Bar $null
Run Code Online (Sandbox Code Playgroud)

这回来了 foo : Cannot bind argument to parameter 'Bar' because it is an empty string.

同样,使它成为一个数组也失败了:

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.
Run Code Online (Sandbox Code Playgroud)

它编程术语完全有可能有一个接受强制可为空参数的函数,但我找不到在PowerShell中这样做的方法.

怎么做?

Roh*_*rds 29

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

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

    Write-Host $Bar
}

Foo -Bar $null
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请查看about_Functions_Advanced_Parameters帮助主题.

请注意,PowerShell会在参数绑定期间将$ null值强制转换为某些类型的实例,例如,[string] $null变为空字符串并[int] $null变为0.要解决此问题,您可以选择以下几种方法:

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


cog*_*el0 21

正如Rohn Edwards的回答中所提到的,[AllowNull()]和/或是[AllowEmptyString()]解决方案的一部分,但需要考虑一些事项.

尽管问题中给出的示例是带有类型字符串,但标题上的问题是如何将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:\>
Run Code Online (Sandbox Code Playgroud)

分析结果:

  • 传递$null给[int]返回[int]具有值的对象0
  • 传递$null给一个[bool]返回一个[bool]有价值的对象False
  • 路过$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
Run Code Online (Sandbox Code Playgroud)

显然,如果它是a [bool]的值,False如果它是一个[string]值将是''

因此,当我们有大多数标准类型的强制参数并且我们分配它时$null,我们没有得到$null,而是该类型的"默认值".

例:

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

Foo -Bar $null
> 0
Run Code Online (Sandbox Code Playgroud)

注意那里根本没有[AllowNull()],但它仍然返回一个0.

A [string]在某种意义上略有不同,因为它不允许在强制参数上使用空字符串,这就是问题中的示例失败的原因.[AllowNull()]也没有解决它,因为空字符串不一样$null,所以我们需要使用[AllowEmptyString()].其他任何事情都会失败.

那么,在哪里[AllowNull()]发挥作用,以及如何将"真实"传递$null给int,bool,wmi等?

int和bool都不是可空类型,所以为了向它们传递"真实" $null,你需要使它们可以为空:

Function Foo {
    Param (
        [Parameter(Mandatory = $true)][AllowNull()][System.Nullable[int]] $Bar
    )
    Write-Host $Bar
}
Run Code Online (Sandbox Code Playgroud)

这允许将"true" $null传递给int,显然在调用Write-Host它时将其转换$null为字符串意味着我们最终''会再次输出,因此它仍然会输出一些内容,但它是一个"true" $null传递.

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

至于制作一个[string]真正可以为空的东西,那个仍然无法逃避我的努力:

[System.Nullable[string]]
Run Code Online (Sandbox Code Playgroud)

返回错误.很可能因为a system.string已经可以为空了,尽管PowerShell似乎并没有这样看待它.

编辑

我只是注意到了

[bool] $null
Run Code Online (Sandbox Code Playgroud)

被胁迫False,做......

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

Foo -Bar $null
Run Code Online (Sandbox Code Playgroud)

抛出以下错误:

Foo : Cannot process argument transformation on parameter 'Bar'. Cannot convert value "" to type "System.Boolean".
Run Code Online (Sandbox Code Playgroud)

这是非常离奇的,更是如此,因为[switch]在上面的函数中使用而不是[bool]工作.


Jep*_*sen 7

首先,添加一个AllowNull属性:

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

    Write-Host $Bar
}
Run Code Online (Sandbox Code Playgroud)

然后,当您调用该函数时,请注意,$null当使用 for 时,它[string]会变成空字符串,而不是空引用。因此(自 PowerShell 3 (2012) 起)使用[NullString]::Value如下:

Foo -Bar ([NullString]::Value)
Run Code Online (Sandbox Code Playgroud)

请参阅class的文档System.Management.Automation.Language.NullString。


编辑:从调用站点来看,这似乎有效,但一旦您到达Write-Host函数内的 cmdlet,$Bar它将再次变成空字符串。请参阅下面的评论。我们必须得出结论,PowerShell 坚持字符串必须是这样的。请注意NullString(这在其他情况下对我有用)在其文档中仅承诺在将 null “传递到 .NET 方法”时有用。