Как написать PowerShell CmdLet, который будет принимать параметр типа System.Type?
Я хочу передать Type
к пользовательскому CmdLet, следующим образом:
PS> "1" | My-CmdLet -Check [System.String]
Я хочу использовать -Check
параметр в качестве аргумента типа для -Is
Оператор в моем CmdLet:
Function My-CmdLet {
param(
${Actual},
[System.String]
${Check} # <-- I want to pass a type here
)
if (-not ($Actual -Is [Type] $Check)) {
# ...
}
}
Когда вызывается следующим образом:
PS> My-CmdLet 1 -Check [System.String]
Результаты в ошибке:
Cannot convert the "[System.String]" value of type "System.String" to type "System.Type". At MycmdLet.ps1:19 char:9
+ if (-not ($Actual -Is [Type] $ExpectedType)) {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToType
Я пытался с помощью [System.String]
, [System.Type]
[System.Object]
, [System.RunTimeType]
как тип для Check
параметр, но ни один из тех, кажется, не работает.
Для сравнения:
Я могу передать тип командлету Where-Object следующим образом:
PS> Get-Process | Where-Object StartTime -Is [System.Datetime]
(В этом случае значение "[System.DateTime]" передается параметру CmdLet $Value
который имеет тип [System.Object]
)
Я могу использовать тип с -Is
Оператор, как это:
PS> "1" -Is [System.String]
True
Как мне объявить -Check
параметр в моем CmdLet?
3 ответа
[System.String]
(обратите внимание на квадратные скобки) является выражением, и поэтому оно не может быть значением параметра, не будучи заключенным в выражение группировки ()
или подвыражение $()
, Это просто ярлык PowerShell для чего-то вроде [type]::GetType("System.String")
(typeof()
в с #).
System.String
однако это строка, которую автоматическое преобразование типов PowerShell успешно преобразует в Type
-объект.
function Test-Type
{
param(
[Parameter(Mandatory=$true,ValueFromPipeLine=$true)]
[PSObject]$Object,
[Parameter(Mandatory=$true)]
[System.Type]$Type
)
$Object -is $Type
}
Test-Type "c" -Type ([string])
1 | Test-Type -Type string
1 | Test-Type -Type ([int])
"1" | Test-Type -Type string
#Output
True
False
True
True
В качестве альтернативы вы можете использовать строковый параметр и преобразовать его в Type
-объект себя внутри своей функции. Таким образом, вы можете удалить квадратные скобки самостоятельно, чтобы преобразование типов работало. Как это:
function Test-Type
{
param(
[Parameter(Mandatory=$true,ValueFromPipeLine=$true)]
[PSObject]$Object,
[Parameter(Mandatory=$true)]
[string]$Type
)
#Remove square brackets and convert to type-object
$Type = [System.Type]($Type -replace '^\[(.*)\]$', '$1')
$Object -is $Type
}
Test-Type "c" -Type [string]
1 | Test-Type -Type string
1 | Test-Type -Type [int]
"1" | Test-Type -Type string
#Output
True
False
True
True
По какой-то причине вы просто не объявите параметр типа System.Type
на первом месте?
function Get-FullyQualifiedTypeName
{
param([System.Type]$Type)
Write-Host $Type.FullName
}
Если вы передаете фактический Type
, это будет принято, в противном случае парсер попытается преобразовать вашу (частичную) строку типа имя в фактическую [type]
для тебя. Не нужно повторно реализовывать то, что парсер уже делает для вас!
PS> Get-FullyQualifiedTypeName $([psobject])
System.Management.Automation.PSObject
PS> Get-FullyQualifiedTypeName string
System.String
Так что в вашем случае вы бы сделали что-то вроде
function Check-Type
{
param(
[Parameter(Mandatory,ValueFromPipeLine)]
[psobject]$Actual,
[Parameter(Mandatory)]
[System.Type]$Check
)
$Actual -is $Check
}
Должен получить то, что вы хотите:
PS> "1" |Check-Type -Check string
True
PS> "1" |Check-Type -Check int
False
PS> 1 |Check-Type -Check int
True
Объявите параметр как строку и приведите его через [тип].
Например:
$a=1
$b="System.Int32"
$a -is [type]$b
Это должно вернуть $true.