Проверка параметров функции в Powershell

#powershell #validation #parameters #casting

Вопрос:

Почему приведенный параметр [string] со значением «$null «в этом примере никогда не выдает ошибку (пустую или $null), но строка со значением «$null» всегда выдает ошибку? Я бы ожидал, что при передаче обязательного параметра он проверяется на наличие $null/пустоты, и поэтому в этих случаях всегда возникает ошибка:

 Function test_M_NoE ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $x ) {}

# test cases. Uncomment one:
[string]$x = [string]$null 
# $x = [string]$null
# [string]$x = $null
# $x = $null 

"1:"; test_M_NoE [string]$x # never error
"2:"; test_M_NoE $x         # always error
 

Комментарии:

1. Преобразование $null в [string] в PowerShell приводит к пустой строке (например, "" или [String]::Empty ), поэтому переданный аргумент на самом деле никогда $null не используется после приведения [string] . Но в вашем случае [string]$x это не фактическое приведенное выражение — оно анализируется в режиме аргумента и интерпретируется как расширяемая строка, например. ничем не отличается от этого test_M_NoE "[string]$x"

2. @MathiasR.Jessen Хорошо, но пустая строка также должна выдавать (ValidateNotNullOrEmpty), и это всегда происходит в последнем операторе. Почему бы и нет, если я приведу параметр?

3. Выражение "[string]$null" приводит к непустой строке

4. $x = [строка]$null; test_M_NoE $x выдает ошибку. В чем разница?

Ответ №1:

Причина, по которой это работает:

 test_M_NoE [string]$x
 

Это то, что [string]$x интерпретируется не так, как вы ожидаете.

Давайте изменим определение вашей тестовой функции, чтобы помочь нам лучше понять, что происходит на самом деле:

 function test_M_NoE {
  param(
    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [string]$x
  )

  Write-Host "Argument value passed was: '$x'"
}
 

А теперь давайте попробуем еще раз:

 PS ~> $x = $null
PS ~> test_M_NoE [string]$x
Argument value passed was: '[string]'
 

Ага! Выражение аргумента [string]$x не привело к пустой строке — оно привело к буквальному строковому значению [string] .

Это связано с тем, что PowerShell пытается анализировать аргументы команд иначе, чем что-либо другое. Из раздела about_Parsing справки:

Режим аргументов предназначен для анализа аргументов и параметров команд в среде командной оболочки. Все входные данные обрабатываются как расширяемая строка, если только в ней не используется один из следующих синтаксисов: […]

Так что на самом деле PowerShell интерпретирует наше выражение аргумента как строку в двойных кавычках:

 test_M_NoE "[string]$x"
 

В этот момент поведение имеет смысл — $x есть $null , поэтому оно оценивается как пустая строка, и поэтому результат выражения "[string]$x" является справедливым [string] .

Заключите выражение аргумента в оператор $(...) подвыражения, чтобы оно оценивалось как выражение значения, а не как расширяемая строка:

 test_M_NoE $([string]$x)
 

Комментарии:

1. Теперь это имеет смысл, спасибо. Хотя для меня это было очень неожиданно. Поэтому, как следствие, я полагаю, что вообще не следует приводить параметры функции и всегда убеждаться, что параметр уже имеет правильный тип, верно?

2. @jamacoe нет, вовсе нет. Моя рекомендация была бы такой: ничего не делайте — PowerShell автоматически попытается преобразовать/принудить аргумент к целевому типу, поэтому ваши попытки вручную преобразовать аргумент в [string] явное совершенно не нужны.