Réponses:
Powershell 7 introduit la fusion native null, l'attribution conditionnelle nulle et les opérateurs ternaires dans Powershell.
Coalescence nulle
$null ?? 100 # Result is 100
"Evaluated" ?? (Expensive-Operation "Not Evaluated") # Right side here is not evaluated
Affectation conditionnelle nulle
$x = $null
$x ??= 100 # $x is now 100
$x ??= 200 # $x remains 100
Opérateur ternaire
$true ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"
Pas besoin des extensions de communauté Powershell, vous pouvez utiliser les instructions Powershell if standard comme expression:
variable = if (condition) { expr1 } else { expr2 }
Donc, aux remplacements de votre première expression C # de:
var s = myval ?? "new value";
devient l'un des suivants (selon la préférence):
$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }
ou selon ce que $ myval pourrait contenir, vous pourriez utiliser:
$s = if ($myval) { $myval } else { "new value" }
et la deuxième expression C # est mappée de la même manière:
var x = myval == null ? "" : otherval;
devient
$x = if ($myval -eq $null) { "" } else { $otherval }
Maintenant, pour être honnête, ils ne sont pas très rapides et loin d'être aussi confortables à utiliser que les formulaires C #.
Vous pouvez également envisager de l'envelopper dans une fonction très simple pour rendre les choses plus lisibles:
function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }
$s = Coalesce $myval "new value"
ou éventuellement, IfNull:
function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }
$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval
Comme vous pouvez le voir, une fonction très simple peut vous donner un peu de liberté de syntaxe.
MISE À JOUR: Une option supplémentaire à considérer dans le mix est une fonction IsTrue plus générique:
function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }
$x = IfTrue ($myval -eq $null) "" $otherval
Combinez ensuite cela est la capacité de Powershell à déclarer des alias qui ressemblent un peu à des opérateurs, vous vous retrouvez avec:
New-Alias "??" Coalesce
$s = ?? $myval "new value"
New-Alias "?:" IfTrue
$ans = ?: ($q -eq "meaning of life") 42 $otherval
De toute évidence, ce ne sera pas du goût de tout le monde, mais c'est peut-être ce que vous recherchez.
Comme le note Thomas, une autre différence subtile entre la version C # et la version ci-dessus est que C # effectue un court-circuit des arguments, mais les versions Powershell impliquant des fonctions / alias évalueront toujours tous les arguments. Si cela pose un problème, utilisez le if
formulaire d'expression.
The variable '$myval' cannot be retrieved because it has not been set.
.
$myval = $null
avant de faire le test, l'erreur devrait disparaître.
$null -ne $a
ne trouvez pas de référence décente maintenant, mais c'est une pratique de longue date.
PowerShell 7 introduit de nombreuses nouvelles fonctionnalités et migre de .NET Framework vers .NET Core. À la mi-2020, il n'a pas complètement remplacé les versions héritées de PowerShell en raison de la dépendance à .NET Core, mais Microsoft a indiqué qu'il prévoyait que la famille Core remplace à terme la famille Framework héritée. Au moment où vous lirez ceci, une version compatible de PowerShell peut être préinstallée sur votre système; sinon, voir https://github.com/powershell/powershell .
Selon la documentation , les opérateurs suivants sont pris en charge par défaut dans PowerShell 7.0:
??
??=
... ? ... : ...
Celles-ci fonctionnent comme vous vous en doutez pour une fusion nulle:
$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'
Depuis qu'un opérateur ternaire a été introduit, ce qui suit est désormais possible, bien que ce ne soit pas nécessaire étant donné l'ajout d'un opérateur de fusion nul:
$x = $a -eq $null ? $b : $a
À partir de la version 7.0, les éléments suivants sont également disponibles si la PSNullConditionalOperators
fonctionnalité facultative est activée , comme expliqué dans la documentation ( 1 , 2 ):
?.
?[]
Ceux-ci ont quelques mises en garde:
${}
si elles sont suivies par l'un des opérateurs expérimentaux car les points d'interrogation sont autorisés dans les noms de variables. On ne sait pas si ce sera le cas si / quand les fonctionnalités passeront du statut expérimental (voir le numéro 11379 ). Par exemple, ${x}?.Test()
utilise l'opérateur new, mais $x?.Test()
s'exécute Test()
sur une variable nommée$x?
.?(
opérateur comme on pourrait s'y attendre si vous venez de TypeScript. Ce qui suit ne fonctionnera pas:$x.Test?()
Les versions de PowerShell antérieures à 7 ont un opérateur de fusion nul réel, ou au moins un opérateur capable d'un tel comportement. Cet opérateur est -ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
C'est un peu plus polyvalent qu'un opérateur de fusion nul, car il crée un tableau de tous les éléments non nuls:
$items = $null, 'alpha', 5, 0, '', @(), $null, $true, $false
$instances = $items -ne $null
[string]::Join(', ', ($instances | ForEach-Object -Process { $_.GetType() }))
# Result:
System.String, System.Int32, System.Int32, System.String, System.Object[],
System.Boolean, System.Boolean
-eq
fonctionne de la même manière, ce qui est utile pour compter les entrées nulles:
($null, 'a', $null -eq $null).Length
# Result:
2
Mais de toute façon, voici un cas typique pour refléter l' ??
opérateur de C # :
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
Cette explication est basée sur une suggestion de modification d'un utilisateur anonyme. Merci, qui que vous soyez!
En fonction de l'ordre des opérations, cela fonctionne dans l'ordre suivant:
,
opérateur crée un tableau de valeurs à tester.-ne
opérateur filtre tous les éléments du tableau qui correspondent à la valeur spécifiée - dans ce cas, null. Le résultat est un tableau de valeurs non nulles dans le même ordre que le tableau créé à l'étape 1.[0]
est utilisé pour sélectionner le premier élément du tableau filtré.Simplifier cela:
Contrairement à l'opérateur de fusion nul de C #, chaque expression possible sera évaluée, puisque la première étape consiste à créer un tableau.
function DidItRun($a) { Write-Host "It ran with $a"; return $a }
et exécutez ((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0]
pour voir cela.
,
a une priorité si élevée. Pour quiconque ne ($null, 'alpha', 1 -ne $null)[0]
sait pas comment cela fonctionne, c'est le même que (($null, 'alpha', 1) -ne $null)[0]
. En fait, les deux seuls opérateurs «tiret» avec une priorité plus élevée sont -split
et -join
(et un tiret unaire? C'est-à-dire. -4
Ou -'56'
).
Il ne s'agit que d'une demi-réponse à la première moitié de la question, donc un quart de réponse si vous voulez, mais il existe une alternative beaucoup plus simple à l'opérateur de fusion nul à condition que la valeur par défaut que vous souhaitez utiliser soit en fait la valeur par défaut du type :
string s = myval ?? "";
Peut être écrit dans Powershell comme:
([string]myval)
Ou
int d = myval ?? 0;
se traduit par Powershell:
([int]myval)
J'ai trouvé le premier d'entre eux utile lors du traitement d'un élément xml qui pourrait ne pas exister et qui, s'il existait, pourrait avoir des espaces non désirés autour de lui:
$name = ([string]$row.td[0]).Trim()
La conversion en chaîne protège contre la nullité de l'élément et évite tout risque d' Trim()
échec.
([string]$null)
-> ""
semble être un "effet secondaire utile, mais malheureux" :(
$null, $null, 3 | Select -First 1
Retour
3
Si vous installez le module d'extensions de communauté Powershell, vous pouvez utiliser:
?? est l'alias d'Invoke-NullCoalescing.
$s = ?? {$myval} {"New Value"}
?: est l'alias d'Invoke-Ternary.
$x = ?: {$myval -eq $null} {""} {$otherval}
Enfin, PowerShell 7 a des opérateurs d'affectation Null Coalescing !
PS > $null ?? "a"
a
PS > "x" ?? "y"
x
PS > $x = $null
PS > $x ??= "abc"
PS > $x
abc
PS > $x ??= "xyz"
PS > $x
abc
@($null,$null,"val1","val2",5) | select -First 1
Souvent, je trouve que je dois également traiter une chaîne vide comme nulle lors de l'utilisation de coalesce. J'ai fini par écrire une fonction pour cela, qui utilise la solution de Zenexer pour la fusion pour la simple fusion nulle, puis j'ai utilisé Keith Hill pour la vérification nulle ou vide, et j'ai ajouté cela comme indicateur afin que ma fonction puisse faire les deux.
L'un des avantages de cette fonction est qu'elle gère également le fait d'avoir tous les éléments nuls (ou vides), sans lever d'exception. Il peut également être utilisé pour de nombreuses variables d'entrée arbitraires, grâce à la façon dont PowerShell gère les entrées de tableau.
function Coalesce([string[]] $StringsToLookThrough, [switch]$EmptyStringAsNull) {
if ($EmptyStringAsNull.IsPresent) {
return ($StringsToLookThrough | Where-Object { $_ } | Select-Object -first 1)
} else {
return (($StringsToLookThrough -ne $null) | Select-Object -first 1)
}
}
Cela produit les résultats de test suivants:
Null coallesce tests:
1 (w/o flag) - empty/null/'end' :
1 (with flag) - empty/null/'end' : end
2 (w/o flag) - empty/null :
2 (with flag) - empty/null :
3 (w/o flag) - empty/null/$false/'end' :
3 (with flag) - empty/null/$false/'end' : False
4 (w/o flag) - empty/null/"$false"/'end' :
4 (with flag) - empty/null/"$false"/'end' : False
5 (w/o flag) - empty/'false'/null/"$false"/'end':
5 (with flag) - empty/'false'/null/"$false"/'end': false
Code de test:
Write-Host "Null coalesce tests:"
Write-Host "1 (w/o flag) - empty/null/'end' :" (Coalesce '', $null, 'end')
Write-Host "1 (with flag) - empty/null/'end' :" (Coalesce '', $null, 'end' -EmptyStringAsNull)
Write-Host "2 (w/o flag) - empty/null :" (Coalesce('', $null))
Write-Host "2 (with flag) - empty/null :" (Coalesce('', $null) -EmptyStringAsNull)
Write-Host "3 (w/o flag) - empty/null/`$false/'end' :" (Coalesce '', $null, $false, 'end')
Write-Host "3 (with flag) - empty/null/`$false/'end' :" (Coalesce '', $null, $false, 'end' -EmptyStringAsNull)
Write-Host "4 (w/o flag) - empty/null/`"`$false`"/'end' :" (Coalesce '', $null, "$false", 'end')
Write-Host "4 (with flag) - empty/null/`"`$false`"/'end' :" (Coalesce '', $null, "$false", 'end' -EmptyStringAsNull)
Write-Host "5 (w/o flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end')
Write-Host "5 (with flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end' -EmptyStringAsNull)
Le plus proche que je puisse obtenir est: $Val = $MyVal |?? "Default Value"
J'ai implémenté l' opérateur de fusion nul pour ce qui précède comme ceci:
function NullCoalesc {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$Default
)
if ($Value) { $Value } else { $Default }
}
Set-Alias -Name "??" -Value NullCoalesc
L' opérateur ternaire conditionnel pourrait être implémenté de manière similaire.
function ConditionalTernary {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$First,
[Parameter(Position=1)]$Second
)
if ($Value) { $First } else { $Second }
}
Set-Alias -Name "?:" -Value ConditionalTernary
Et utilisé comme: $Val = $MyVal |?: $MyVal "Default Value"