При пустом массиве в качестве прямого конвейерного ввода ничего отправляется по конвейеру , потому что массив имеет перечисление и поскольку перечислять нечего - пустой массив не имеет элементов - блок скрипта Where
никогда не выполняется:
# The empty array is enumerated, and since there's nothing to enumerate,
# the Where[-Object] script block is never invoked.
@() | Where { $_.name -eq "Baz" }
В отличие от этого, "[]" | ConvertFrom-Json
создает пустой массив в качестве единственного выходного объекта , а не перечисляет его (несуществующие) элементы, поскольку ConvertFrom-Json
по типу не делает не перечислять элементы массивов, которые он выводит ; это эквивалент:
# Empty array is sent as a single object through the pipeline.
# The Where script block is invoked once and sees $_ as that empty array.
Write-Output -NoEnumerate @() | Where { $_.name -eq "Baz" }
Поведение
ConvertFrom-Json
удивительно в контексте PowerShell - командлеты обычно перечисляют несколько выходов - но имеет смысл в контексте анализа JSON ; в конце концов, информация будет потеряна , если ConvertFrom-Json
перечислит пустой массив, учитывая, что вы не сможете отличить это от пустого ввода JSON ("" | ConvertFrom-Json
).
Это напряжение обсуждается в этом выпуске GitHub .
Консенсус заключается в том, что оба варианта использования являются законными и что пользователи должны иметь выбор между двумя вариантами поведения - перечислением или нет - с помощью переключателя ; Начиная с PowerShell Core 6.2.0 формальное решение не было принято, но если необходимо сохранить обратную совместимость, это должно быть поведение перечисления, которое будет opt-in (например, -Enumerate
) .
Если требуется перечисление, то пока что - неясный - обходной путь - принудительное перечисление , просто заключив вызов ConvertFrom-Json
в (...)
(который преобразует его в выражение , а выражения всегда перечисляют выходные данные команды при использовании в конвейере):
# (...) around the ConvertFrom-Json call forces enumeration of its output.
# The empty array has nothing to enumerate, so the Where script block is never invoked.
("[]" | ConvertFrom-Json) | Where { $_.name -eq "Baz" }
Что касается того, что вы пытались : ваша попытка получить доступ к свойству .Count
и ваше использование @(...)
:
$y = ("[]" | ConvertFrom-Json) | Where { $_.name -eq "Baz" }
$y.Count # Fails with Set-StrictMode -Version 2 or higher
С вызовом ConvertFrom-Json
, заключенным в (...)
, ваша общая команда возвращает «ничто»: свободно говоря, $null
, но, точнее, «null-значение со значением массива», которое является [System.Management.Automation.Internal.AutomationNull]::Value
singleton это указывает на отсутствие вывода команды. (В большинстве случаев последний обрабатывается так же, как $null
, хотя, в частности, не используется в качестве входных данных конвейера.)
[System.Management.Automation.Internal.AutomationNull]::Value
не имеет свойства .Count
, поэтому при действии Set-StrictMode -Version 2
или выше вы получите ошибку The property 'count' cannot be found on this object.
.
Оборачивая весь конвейер в @(...)
, оператор подвыражения массива, вы гарантируете обработку выходных данных как array , который, с помощью [null output с массивом, создает пустой массив - который имеет свойство .Count
.
Обратите внимание, что вы должны иметь возможность вызывать .Count
на $null
и [System.Management.Automation.Internal.AutomationNull]::Value
, учитывая, что PowerShell добавляет свойство .Count
к каждому объект, если он еще не существует, включая скаляры, в похвальном стремлении унифицировать обработку коллекций и скаляров.
То есть с Set-StrictMode
, установленным на -Off
(по умолчанию) или на -Version 1
, следующее работает и работает - разумно - возвращает 0
:
# With Set-StrictMode set to -Off (the default) or -Version 1:
# $null sensibly has a count of 0.
PS> $null.Count
0
# So does the "array-valued null", [System.Management.Automation.Internal.AutomationNull]::Value
# `. {}` is a simple way to produce it.
PS> (. {}).Count # `. {}` outputs
0
То, что вышеупомянутое в настоящее время не не работает с Set-StrictMode -Version 2
или выше (по состоянию на PowerShell Core 6.2.0), должно рассматриваться как ошибка , как сообщалось в этом выпуске GitHub (не менее Джеффри Сновером).