2010-12-05 7 views
18

a menudo tengo la siguiente situación en mi código de PowerShell: Tengo una función o propiedad que devuelve una colección de objetos, o $null. Si inserta los resultados en la tubería, también maneja un elemento en la tubería si $null es el único elemento.

Ejemplo:

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

Si no hay características ($ Project.Features devuelve $ null), verá una sola línea con "Nombre de la característica:".

veo tres maneras de resolver este:

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

o

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

o

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

Pero en realidad no me gusta ninguno de estos enfoques, pero ¿qué ¿Ves como el mejor enfoque?

Respuesta

25

No creo que a le guste el hecho de que tanto "foreach ($ a in $ null) {}" como "$ null | foreach-object {}" iteren una vez. Lamentablemente, no hay otra forma de hacerlo que las formas que ha demostrado. Usted podría ser pithier:

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

la ?{$_} es la abreviatura de where-object {$_ -ne $null} como $null evaluado como una expresión booleana será tratado como $false

he un filtro definido en el perfil de esta manera:

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

Uso:

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

Un filtro es lo mismo que una función, excepto que el bloque predeterminado es el proceso {} no final {}.

ACTUALIZACIÓN: A partir de PowerShell 3.0, $null ya no es iterable como una colección. ¡Hurra!

-Oisin

+5

El problema con la abreviación concisa es que rechazará cualquier cosa que coacciona a 'false', que incluye cosas como' 0', '" '', '@()', '@ (0)', ... Probablemente esperaría que 'Skip-Null' omita' '$ null'. Sé que en el contexto de esta pregunta, el resultado es el mismo, pero para un filtro que también podría usarse en otros lugares ... – Joey

+0

@joey buen punto. – x0n

+0

lamentablemente '@() |? {$ False}' aún devuelve $ null en lugar de devolver una lista vacía – ekkis

12

Si usted puede modificar su función, tienen que devolver una colección vacía/matriz en lugar de $ nulo:

PS> function Empty { $null } 
PS> Empty | %{'hi'} 
hi 

PS> function Empty { @() } 
PS> Empty | %{'hi'} 

De lo contrario, ir con lo que sugiere Oisin aunque yo sugeriría una ligera tweak:

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

De lo contrario esto también filtrar 0 y $false.

Actualización 4-30-2012: Este problema se corrigió en PowerShell v3. V3 no iterará sobre un valor $ nulo escalar.

+0

¡Por qué no puedo aceptar solo una respuesta! Ambos son geniales, ¡gracias chicos! Le di a Oisin la "respuesta", Keith ya tiene el punto más importante :-) –

+0

¿Cuáles son las posibilidades de que haya estado viendo esta misma respuesta cuando la editó casi 17 meses después de su publicación? ¿Hay un cmdlet para calcular eso? – BACON

+0

@BACON Definitivamente no es una coincidencia. Me di cuenta a través de mi bandeja de entrada SO que había publicado un comentario sobre una de mis respuestas. :-) Solo pensé que sería bueno señalar que esto no es un problema en V3. –

2

Una nota rápida a la respuesta de Keith para completarla

Personalmente, me volvería nada. Tiene sentido:

PS> function Empty { if ('a' -eq 'b') { 'equal' } } 
PS> Empty | % { write-host result is $_ } 

Pero ahora están en problemas si asigna resultado de Empty a una variable:

PS> $v = Empty 
PS> $v | % { write-host result is $_ } 

Hay un pequeño truco para hacer que funcione. Simplemente envuelva el resultado de Empty como una matriz de esta manera:

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 
+1

Ese es el enfoque que uso hoy * si * No controlo la definición de el comando que se invoca. De lo contrario, devuelvo una matriz vacía si la función normal devuelve múltiples elementos, de modo que me gustaría extenderme sobre ella; muchas veces me he olvidado de envolver @(). :-) –

+0

@Keith, creo que escribió un gran artículo sobre este comportamiento complicado. Puede vincularlo aquí, otros deben leerlo, definitivamente;) – stej

2

Otra posibilidad:

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

Más información en about_Continue

Cuestiones relacionadas