考虑这个函数:
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]
正确解析。
我在解释Trace命令的输出方面没有经验。我确实注意到[string]
的输出包括以下行:
BIND arg[string]到param[PsCustomObject]SUCCESSFUL
看起来PowerShell正在考虑将[string]
作为[PsCustomObject]
。但CCD_ 10评估为CCD_。
这一切都给我留下了以下问题:
- 为什么PowerShell不能根据
[string]
和[pscustomobject]
之间的类型差异来选择参数集 - 原因是PowerShell认为
[string]
是[pscustomobject]
吗?如果是这样,为什么会这样 - 有没有一种变通方法可以让我使用不同的类型来选择不同的参数集
我相信这是因为任何东西都可以被广播到[PSObject]
([PSCustomObject]
(。PowerShell尝试将值合并到目标类型。这就是为什么当你有一个[int]
的参数时,你可以传递"5"
,它会起作用,或者为什么当你的参数是[ipaddress]
时,你能给它一个字符串"1.2.3.4"
。
因此,在参数绑定过程中,当您传递[string]
或[hashtable]
时,会发生的情况是它成功地将其绑定到[pscustomboject]
参数,以及(至少(其他参数之一,因此它无法解析集合。
我不认为有任何方法可以关闭这种行为或使其"更严格"。
顺便说一句,任何东西都可以被广播到[PSObject]
的原因是,在PowerShell中,每个对象都已经是[PSObject]
了!这也是您可以将成员添加到任何对象的任何实例的原因。PowerShell使这一切变得非常透明,这就是为什么正如您所说,它在这种情况下(以及其他一些情况下(违反了最小惊喜原则。
如果您从C#中与PowerShell进行交互,那么[PSObject]
中的所有内容都会变得更加明显(在许多情况下也很烦人(,这就是我第一次意识到这一点的原因。