PowerShell - «запись-вывод» против «возврата» в функциях - PullRequest
0 голосов
/ 04 июля 2018

Я использую PowerShell уже несколько лет, и мне показалось, что я справляюсь с некоторыми из его более «эксцентричных» действий, но я столкнулся с проблемой, которую я не могу ни осознать, ни понять. .

Я всегда использовал «return» для возврата значений из функций, но недавно я подумал, что мне стоит взглянуть на Write-Output в качестве альтернативы. Однако, поскольку PowerShell является PowerShell, я обнаружил нечто, что, кажется, не имеет смысла (по крайней мере для меня):

function Invoke-X{ write-output @{ "aaa" = "bbb" } };
function Invoke-Y{ return @{ "aaa" = "bbb" } };

$x = Invoke-X;
$y = Invoke-Y;

write-host $x.GetType().FullName
write-host $y.GetType().FullName

write-host ($x -is [hashtable])
write-host ($y -is [hashtable])

write-host ($x -is [pscustomobject])
write-host ($y -is [pscustomobject])

выход:

System.Collections.Hashtable
System.Collections.Hashtable
True
True
True
False

В чем разница между $ x и $ y (или «write-output» и «return»), которые означают, что они оба являются хеш-таблицами, но только один из них - это «объект-объект»? И есть ли обобщенный способ определения отличия от кода, кроме явной проверки, является ли каждая хеш-таблица, имеющаяся у меня в переменной, также объектом pscustomobject)?

Моя таблица $ PSVersionTable выглядит так, если это поведение относится к конкретной версии PowerShell:

Name                           Value
----                           -----
PSVersion                      5.1.16299.492
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.16299.492
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Приветствия

M

1 Ответ

0 голосов
/ 04 июля 2018

return и [pscustomobject] здесь, в некотором смысле, красные сельди.

То, к чему это сводится:

  • Неявный вывод / выражение в сравнении с производимым командлетом выводом; использование return относится к первой категории, использование Write-Output ко второй.

  • объекты, заключенные в в основном невидимые [psobject] экземпляры только в командлет выходные данные.

# implicit / expression output: NO [psobject] wrapper:
@{ "aaa" = "bbb" } -is [psobject] # -> $False

# Cmdlet-produced output: [psobject]-wrapped
(Write-Output @{ "aaa" = "bbb" }) -is [psobject]  # -> $True

Обратите внимание, что, что удивительно, [pscustomobject] совпадает с [psobject]: они оба относятся к типу [System.Management.Automation.PSObject], который является обычно невидимым вспомогательным типом , который PowerShell использует за кулисами.
(Чтобы добавить к путанице, - это отдельный [System.Management.Automation.PSCustomObject] тип.)

По большей части эта дополнительная оболочка [psobject] является доброкачественной - она ​​в основном ведет себя так же, как обернутый объект напрямую - но есть случаи, когда она вызывает слегка другое поведение (см. Ниже).


И есть ли обобщенный способ определения отличия от кода, кроме явной проверки, является ли каждая хеш-таблица, имеющаяся у меня в переменной, также объектом pscustomobject

Обратите внимание, что хеш-таблица не пользовательский объект PS - он появляется таким образом для - любого - [psobject] -обернутого объекта, поскольку [pscustomobject] совпадает с [psobject].

Чтобы обнаружить настоящий пользовательский объект PS - созданный с помощью [pscustomobject] @{ ... } или New-Object PSCustomObject / New-Object PSObject или созданный такими командлетами, как Select-Object и Import-Csv - используйте:

$obj -is [System.Management.Automation.PSCustomObject] # NOT just [pscustomobject]!

Обратите внимание, что использование связанного оператора -as с настоящим пользовательским объектом PS не работает в Windows PowerShell v5.1 / PowerShell Core v6.1.0 - см. Ниже.

В качестве примера ситуации, когда дополнительная оболочка [psobject] является доброкачественной, вы все равно можете напрямую проверить даже обернутый объект на его тип:

(Write-Output @{ "aaa" = "bbb" }) -is [hashtable]  # $True

То есть, несмотря на упаковщик, -is все еще распознает тип wrapped . Поэтому, как это ни парадоксально, и -is [psobject], и -is [hashtable] возвращают $True в этом случае, даже если эти типы не связаны.


Нет веских причин для этих несоответствий и они кажутся мне утечкой абстракций (реализациями): внутренние конструкции случайно выглядывают из-за занавеса.

Следующие проблемы GitHub обсуждают эти поведения:

...