考虑这个功能:
function Test-Discrimination
{
[CmdletBinding()]
param
(
[parameter(ValueFromPipeline = $true,
Mandatory = $true,
ParameterSetName = 'string')]
[string]
$String,
[parameter(ValueFromPipeline = $true,
Mandatory = $true,
ParameterSetName = 'hashtable')]
[hashtable]
$Hashtable,
[parameter(ValueFromPipeline = $true,
Mandatory = $true,
ParameterSetName = 'pscustomobject')]
[pscustomobject]
$PsCustomObject
)
process
{
$PSCmdlet.ParameterSetName
}
}
管道[pscustomobject]
的行为符合我的预期:
PS C:\> New-Object pscustomobject | Test-Discrimination
pscustomobject
但是,管道[string]
会引发异常:
PS C:\> 'string' | Test-Discrimination
Test-Discrimination : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:12
+ 'string' | Test-Discrimination
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (string:String) [Test-Discrimination], Paramete
rBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Test-Discrimination
[hashtable]
:
PS C:\> @{} | Test-Discrimination
Test-Discrimination : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:7
+ @{} | Test-Discrimination
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.Collections.Hashtable:Hashtable) [Test-
Discrimination], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Test-Discrimination
添加DefaultParameterSetName='hastable'
导致[hashtable]
导致[string]
无法正确解析。
我在解释the output from Trace-Command时没有经验。我注意到[string]
的输出包括这一行:
BIND arg [string] to param [PsCustomObject] SUCCESSFUL
PowerShell似乎认为[string]
是[PsCustomObject]
。但'string' -is [pscustomobject]
评估为$false
。
这给我留下了以下问题:
[string]
和[pscustomobject]
之间的类型差异选择参数集?[string]
是[pscustomobject]
吗?如果是这样,那为什么会这样?答案 0 :(得分:2)
我认为原因是任何事情都可以投放到[PSObject]
([PSCustomObject]
)。 PowerShell尝试将值合并到目标类型。这就是为什么当你有一个[int]
的参数时,你可以传递"5"
它会起作用,或者为什么当你有一个[ipaddress]
的参数时,你可以给它一个字符串{{ 1}}。
因此,在参数绑定期间,传递"1.2.3.4"
或[string]
时发生的情况是,它成功地将其绑定到[hashtable]
参数,以及(至少)其中一个参数其他人,因此无法解决问题。
我不相信有任何办法可以关闭此行为或使其“更严格”。
顺便说一句,任何事情都可以转换为[pscustomboject]
的原因是因为在PowerShell中,每个对象都已经是[PSObject]
!这也是您可以将成员添加到任何对象的任何实例的原因。 PowerShell使这一切都非常透明,这就是为什么如你所说,它违反了这个(以及其他一些情况)最少出人意料的原则。
如果您在C#中与PowerShell交互,那么所有内容都包含在[PSObject]
中的事实变得更加明显(并且在许多情况下令人讨厌),这就是我第一次意识到这种情况。