Передача null в обязательный параметр функции

Фактически моя проблема сводится к следующему:

Я не могу иметь функцию с обязательным параметром и передать $ null этому параметру:

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

    Write-Host $Bar
}

Foo -Bar $null

Это возвращает 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.

В терминах программирования вполне возможно иметь функцию, которая принимает обязательный обнуляемый параметр, но я не могу найти способ сделать это в PowerShell.

Как мне это сделать?

Ответ 1

Как упоминалось в ответе Рона Эдвардса, [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:\>

Анализ результатов:

  • Передача $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

Очевидно, если бы это было [bool] значение с be False, и если бы это было [string], это значение было бы ''

Поэтому, когда у нас есть обязательный параметр стандартных большинства стандартных типов, и мы назначаем его $null, мы не получаем $null, а скорее "значение по умолчанию" для этого типа.

Пример:

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

Foo -Bar $null
> 0

Обратите внимание, что там нет [AllowNull()], но он все равно возвращает 0.

A [string] несколько отличается, в том смысле, что он не разрешает пустые строки по обязательным параметрам, поэтому пример в вопросе не работает. [AllowNull()] также не исправляет его, поскольку пустая строка не совпадает с $null, поэтому нам нужно использовать [AllowEmptyString()]. Ничего другого не удастся.

Итак, где [AllowNull()] входит в игру и как передать "реальный" $null в int, bool, wmi и т.д.?

Ни int, ни bool не являются типами 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]]

Возвращает ошибку. Скорее всего, потому что a 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] работает.

Ответ 2

Вы должны иметь возможность использовать атрибут параметра [AllowEmptyString()] для параметров [string] и/или атрибут параметра [AllowNull()] для других типов. Я добавил атрибут [AllowEmptyString()] к функции из вашего примера:

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

    Write-Host $Bar
}

Foo -Bar $null

Дополнительные сведения см. в разделе справки about_Functions_Advanced_Parameters.

Помните, что PowerShell будет принуждать значение $null в экземпляр некоторых типов во время привязки параметра для обязательных параметров, например, [string] $null становится пустой строкой, а [int] $null становится 0. Чтобы обойти это, у вас есть несколько параметры:

  • Удалить ограничение типа параметра. Вы можете проверить значение $null в вашем коде, а затем применить его к типу, который вы хотите.
  • Используйте System.Nullable(см. другой ответ для этого). Это будет работать только для типов значений.
  • Переосмыслите конструкцию функций, чтобы у вас не было обязательных параметров, которые должны разрешать null.

Ответ 3

Я думаю, вы пропустили ",", чтобы отделить параметры.

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

Ответ 4

Сначала добавьте атрибут AllowNull:

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

    Write-Host $Bar
}

Затем, когда вы вызываете функцию, имейте в виду, что $null при использовании для [string] становится пустой строкой, а не пустой ссылкой. Поэтому (начиная с PowerShell 3 (2012)) используйте [NullString]::Value следующим образом:

Foo -Bar ([NullString]::Value)

См. документацию для класса System.Management.Automation.Language.NullString.


РЕДАКТИРОВАТЬ: С сайта вызова это работает, но вскоре, когда вы достигнете командлета Write-Host внутри функции, $Bar снова станет пустой строкой. См. Комментарии ниже. Мы должны заключить, что PowerShell настаивает на том, что строки должны быть такими. Обратите внимание, что NullString (что было полезно для меня в других случаях) в его документации только promises полезно при передаче null "в .NET-метод" .