2010-12-05 3 views
18

В моем коде PowerShell часто возникает следующая ситуация: у меня есть функция или свойство, которое возвращает коллекцию объектов, или $null. Если вы вставляете результаты в конвейер, вы также обрабатываете элемент в конвейере, если $null является единственным элементом.

Пример:

$Project.Features | Foreach-Object { Write-Host "Feature name: $($_.Name)" } 

Если нет возможности ($ Project.Features возвращает $ Null), вы увидите одну строку с "именем Feature:".

Я вижу три пути решения этой:

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)" } 
    } 
} 

Но на самом деле мне не нравится какой-либо из этих подходов, но что делать вы видите, как лучший подход?

ответ

25

Я не думаю, что кому-то нравится тот факт, что и «foreach ($ a in $ null) {}" и "$ null | foreach-object {}" повторяются один раз. К сожалению, нет другого способа сделать это, чем способы, которые вы продемонстрировали. Вы можете быть pithier:

$null | ?{$_} | % { ... } 

?{$_} представляет собой сокращенную where-object {$_ -ne $null} как $null оценивается как логическое выражение будет рассматриваться как $false

У меня есть фильтр, заданный в моем профиле, как это:

filter Skip-Null { $_|?{ $_ } } 

Использование:

$null | skip-null | foreach { ... } 

Фильтр такой же, как и функция, кроме блока по умолчанию - процесс {} not end {}.

ОБНОВЛЕНИЕ: Начиная с версии PowerShell 3.0, $null уже не является итерируемым как коллекция. Ура!

-Oisin

+5

Проблема с кратким стенографии, что он будет отвергать все, что принуждают to `false`, который включает в себя такие вещи, как` 0`, `` ``, `@()`, `@ (0)`, ... Я бы предположил, что `Skip-Null` фактически пропускает только` $ null`. Я знаю, что в контексте этого вопроса результат будет таким же, но для фильтра, который может быть использован и в другом месте ... – Joey 2012-07-19 19:18:42

+0

@joey хорошая точка. – x0n 2013-04-30 21:01:58

+0

sadly `@() |? {$ False}` все еще возвращает $ null вместо того, чтобы возвращать пустой список – ekkis 2016-11-24 16:51:15

12

Если вы можете изменить вашу функцию, пусть он возвращает пустой массив/коллекция вместо $ 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.

2

Быстрое примечание к ответу Кейта, чтобы завершить это

Лично я бы вернуться ничего. Это имеет смысл:

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 
2

Другая возможность:

$objects | Foreach-Object -Begin{If($_ -eq $null){continue}} -Process {do your stuff here} 

Более подробную информацию в about_Continue

Смежные вопросы