Opérateur ternaire en PowerShell
D'après ce que je sais, PowerShell ne semble pas avoir d'expression intégrée pour le soi-disant opérateur ternaire .
par exemple, dans le langage C, qui supporte l'opérateur ternaire, je pourrais écrire quelque chose comme:
<condition> ? <condition-is-true> : <condition-is-false>;
si cela n'existe pas vraiment dans PowerShell, quelle serait la meilleure façon (c.-à-d. facile à lire et à maintenir) d'accomplir le même résultat?
10 réponses
$result = If ($condition) {"true"} Else {"false"}
tout le reste est une complexité fortuite et donc à éviter.
pour une utilisation dans ou comme une expression, pas seulement une assignation, envelopper dans $()
, ainsi:
write-host $(If ($condition) {"true"} Else {"false"})
la structure Powershell la plus proche que j'ai pu trouver pour imiter c'est:
. ({'condition is false'},{'condition is true'})[$condition]
Par cette PowerShell blog , vous pouvez créer un alias pour définir un ?:
opérateur:
set-alias ?: Invoke-Ternary -Option AllScope -Description "PSCX filter alias"
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse)
{
if (&$decider) {
&$ifTrue
} else {
&$ifFalse
}
}
utilisez - le comme ceci:
$total = ($quantity * $price ) * (?: {$quantity -le 10} {.9} {.75})
moi aussi, j'ai cherché une meilleure réponse, et alors que la solution dans le post D'Edward est "ok", je suis venu avec un beaucoup plus naturel solution dans ce post de blog
court et doux:
# ---------------------------------------------------------------------------
# Name: Invoke-Assignment
# Alias: =
# Author: Garrett Serack (@FearTheCowboy)
# Desc: Enables expressions like the C# operators:
# Ternary:
# <condition> ? <trueresult> : <falseresult>
# e.g.
# status = (age > 50) ? "old" : "young";
# Null-Coalescing
# <value> ?? <value-if-value-is-null>
# e.g.
# name = GetName() ?? "No Name";
#
# Ternary Usage:
# $status == ($age > 50) ? "old" : "young"
#
# Null Coalescing Usage:
# $name = (get-name) ? "No Name"
# ---------------------------------------------------------------------------
# returns the evaluated value of the parameter passed in,
# executing it, if it is a scriptblock
function eval($item) {
if( $item -ne $null ) {
if( $item -is "ScriptBlock" ) {
return & $item
}
return $item
}
return $null
}
# an extended assignment function; implements logic for Ternarys and Null-Coalescing expressions
function Invoke-Assignment {
if( $args ) {
# ternary
if ($p = [array]::IndexOf($args,'?' )+1) {
if (eval($args[0])) {
return eval($args[$p])
}
return eval($args[([array]::IndexOf($args,':',$p))+1])
}
# null-coalescing
if ($p = ([array]::IndexOf($args,'??',$p)+1)) {
if ($result = eval($args[0])) {
return $result
}
return eval($args[$p])
}
# neither ternary or null-coalescing, just a value
return eval($args[0])
}
return $null
}
# alias the function to the equals sign (which doesn't impede the normal use of = )
set-alias = Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment."
ce qui rend facile de faire des choses comme (plus d'exemples dans le blog post):
$message == ($age > 50) ? "Old Man" :"Young Dude"
étant donné qu'un opérateur ternaire est habituellement utilisé pour attribuer une valeur, il doit renvoyer une valeur. C'est ainsi que cela peut fonctionner:
$var=@("value if false","value if true")[[byte](condition)]
stupide, mais travaillant. De plus, cette construction peut être utilisée pour transformer rapidement un int en une autre valeur, il suffit d'ajouter des éléments de tableau et de spécifier une expression qui renvoie des valeurs non négatives basées sur 0.
comme je l'ai déjà utilisé plusieurs fois et que je ne l'ai pas vu énuméré ici, je vais ajouter mon morceau:
$var = @{$true="this is true";$false="this is false"}[1 -eq 1]
le plus laid de tous !
essayez la déclaration switch de powershell comme alternative, surtout pour la cession variable-lignes multiples, mais lisible.
exemple,
$WinVer = switch ( Test-Path $Env:windir\SysWOW64 ) {
$true { "64-bit" }
$false { "32-bit" }
}
"This version of Windows is $WinVer"
PowerShell n'a pas actuellement un en ligne si (ou ternaire si ), mais vous pouvez envisager d'utiliser le cmdlet personnalisé:
IIf <condition> <condition-is-true> <condition-is-false>
Voir: PowerShell Inline If (IIf)
j'ai récemment amélioré (Open PullRequest) les opérateurs ternaires conditionnel et null-coalescing dans la PoweShell lib 'Pscx'
Pls ont un coup d'oeil pour ma solution.
ma branche thématique github: UtilityModule_Invoke-Operators
fonctions:
Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe
Alias
Set-Alias :?: Pscx\Invoke-Ternary -Description "PSCX alias"
Set-Alias ?: Pscx\Invoke-TernaryAsPipe -Description "PSCX alias"
Set-Alias :?? Pscx\Invoke-NullCoalescing -Description "PSCX alias"
Set-Alias ?? Pscx\Invoke-NullCoalescingAsPipe -Description "PSCX alias"
Utilisation
<condition_expression> |?: <true_expression> <false_expression>
<variable_expression> |?? <alternate_expression>
comme expression vous pouvez passer:
$ null, une variable, une expression externe ($b-eq 4) ou un scriptblock {$b-eq 4}
Si une variable dans l'expression variable est $ null ou non existante, l'expression alternative est évaluée comme output.
Voici une approche de fonction personnalisée alternative:
function Test-TernaryOperatorCondition {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
[bool]$ConditionResult
,
[Parameter(Mandatory = $true, Position = 0)]
[PSObject]$ValueIfTrue
,
[Parameter(Mandatory = $true, Position = 1)]
[ValidateSet(':')]
[char]$Colon
,
[Parameter(Mandatory = $true, Position = 2)]
[PSObject]$ValueIfFalse
)
process {
if ($ConditionResult) {
$ValueIfTrue
}
else {
$ValueIfFalse
}
}
}
set-alias -Name '???' -Value 'Test-TernaryOperatorCondition'
exemple
1 -eq 1 |??? 'match' : 'nomatch'
1 -eq 2 |??? 'match' : 'nomatch'
Différences Expliquées
- Pourquoi 3 points d'interrogation au lieu de 1?
- le caractère
?
est déjà un alias pourWhere-Object
. -
??
est utilisé dans d'autres langues comme valeur null opérateur de cogénération, et je voulais éviter toute confusion.
- le caractère
- Pourquoi avons-nous besoin du tuyau avant la commande?
- puisque j'utilise le pipeline pour évaluer ceci, nous avons encore besoin de ce caractère pour Piper la condition dans notre fonction
- que se passe-t-il si je passe en tableau?
- nous obtenons un résultat pour chaque valeur; i.e.
-2..2 |??? 'match' : 'nomatch'
donne:match, match, nomatch, match, match
(i.e. depuis tout int non-zéro évalue àtrue
; tandis que zéro évalue àfalse
). - si vous ne voulez pas cela, convertissez le tableau en un bool;
([bool](-2..2)) |??? 'match' : 'nomatch'
(ou tout simplement:[bool](-2..2) |??? 'match' : 'nomatch'
)
- nous obtenons un résultat pour chaque valeur; i.e.