Почему нельзя определить наборы параметров на основе [string] vs [hashtable] vs [pscustomobject]?

Рассмотрим эту функцию:

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-Command. Я заметил выход для [string] включает в себя эту строку:

BIND arg [string] to param [PsCustomObject] УСПЕШНО

Кажется, что PowerShell рассматривает [string] быть [PsCustomObject], Но 'string' -is [pscustomobject] оценивает $false,

Это все оставляет меня со следующими вопросами:

  1. Почему PowerShell не может выбрать набор параметров на основе различий в типе между [string] и [pscustomobject]?
  2. Причина в том, что PowerShell считает [string] быть [pscustomobject]? Если так, то почему?
  3. Есть ли обходной путь, который позволяет мне использовать разные типы для выбора разных наборов параметров?

1 ответ

Я считаю, что причина этого заключается в том, что все [PSObject] ([PSCustomObject]). PowerShell пытается объединить значения с целевым типом. Вот почему, когда у вас есть параметр, который [int], вы можете пройти "5" и это будет работать, или почему, когда у вас есть параметр, который [ipaddress]Вы можете дать ему строку "1.2.3.4",

Итак, во время привязки параметров, что происходит, когда вы передаете [string] или же [hashtable] является то, что он успешно связывает его с [pscustomboject] параметр, а также (по крайней мере) один из других, и, следовательно, он не может разрешить набор.

Я не верю, что есть какой-либо способ отключить это поведение или сделать его "более строгим".


И, кстати, причина может быть приведена к чему угодно [PSObject] потому что в PowerShell каждый объект [PSObject] уже! По этой же причине вы можете добавлять элементы к любому экземпляру любого объекта. PowerShell делает все это действительно прозрачным, поэтому, как вы сказали, он нарушил принцип наименьшего удивления в этом (и некоторых других случаях).

Если вы взаимодействуете с PowerShell изнутри C#, тот факт, что все обернуто в [PSObject] становится намного более очевидным (и во многих случаях раздражающим), и именно так я впервые понял, что это так.

Другие вопросы по тегам