Как обрабатывать $null в конвейере
В моем коде PowerShell часто возникает следующая ситуация: у меня есть функция или свойство, которое возвращает коллекцию объектов или $null
. Если вы вставляете результаты в конвейер, вы также обрабатываете элемент в конвейере, если $null
- единственный элемент.
Пример:
$Project.Features | Foreach-Object { Write-Host "Feature name: $($_.Name)" }
Если функций нет ($ Project.Features возвращает $null), вы увидите одну строку с названием функции:.
Я вижу три способа решить эту проблему:
if ($Project.Features -ne $null)
{
$Project.Features | Foreach-Object { Write-Host "Feature name: $($_.Name)" }
}
или
$Project.Features | Where-Object {$_ -ne $null) | Foreach-Object {
Write-Host "Feature name: $($_.Name)"
}
или
$Project.Features | Foreach-Object {
if ($_ -ne $null) {
Write-Host "Feature name: $($_.Name)" }
}
}
Но на самом деле мне не нравится какой-либо из этих подходов, но что вы видите как лучший подход?
Ответы
Ответ 1
Мне не кажется, что кому-то нравится тот факт, что и "foreach ($ a в $null) {}" и "$ null\foreach-object {}" повторяются один раз. К сожалению, нет другого способа сделать это, чем способы, которые вы продемонстрировали. Вы можете быть более точными:
$null | ?{$_} | % { ... }
?{$_}
является сокращением для where-object {$_ -ne $null}
, поскольку $null
, оцененное как булево выражение, будет рассматриваться как $false
У меня есть фильтр, определенный в моем профиле:
filter Skip-Null { $_|?{ $_ } }
Использование:
$null | skip-null | foreach { ... }
Фильтр такой же, как и функция, кроме блока по умолчанию - процесс {} not end {}.
ОБНОВЛЕНИЕ. Начиная с версии PowerShell 3.0, $null
уже не является итерируемым как коллекция. Ура!
-Oisin
Ответ 2
Если вы можете изменить свою функцию, верните пустую коллекцию/массив вместо $null:
PS> function Empty { $null }
PS> Empty | %{'hi'}
hi
PS> function Empty { @() }
PS> Empty | %{'hi'}
В противном случае перейдите к тому, что предлагает Oisin, хотя я бы предложил небольшой настрой:
filter Skip-Null { $_|?{ $_ -ne $null } }
В противном случае это также будет фильтровать 0
и $false
.
Обновление 4-30-2012: Эта проблема исправлена в PowerShell v3. V3 не будет перебирать скалярное значение $null.
Ответ 3
Быстрая заметка Кейту, чтобы ответить на него.
Лично я ничего не вернул бы. Это имеет смысл:
PS> function Empty { if ('a' -eq 'b') { 'equal' } }
PS> Empty | % { write-host result is $_ }
Но теперь у вас проблемы, если вы назначаете результат из Empty
переменной:
PS> $v = Empty
PS> $v | % { write-host result is $_ }
Есть небольшой трюк, чтобы заставить его работать. Просто обведите результат из Empty
в виде массива, подобного этому:
PS> $v = @(Empty)
PS> $v | % { write-host result is $_ }
PS> $v.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
PS> $v.Length
0
Ответ 4
Другая возможность:
$objects | Foreach-Object -Begin{If($_ -eq $null){continue}} -Process {do your stuff here}
Дополнительная информация в about_Continue