Odpowiedzi:
Powershell 7 wprowadza natywne łączenie wartości null, przypisanie warunkowe wartości null i operatory trójskładnikowe w programie PowerShell.
Null Coalescing
$null ?? 100 # Result is 100
"Evaluated" ?? (Expensive-Operation "Not Evaluated") # Right side here is not evaluated
Przypisanie warunkowe o wartości Null
$x = $null
$x ??= 100 # $x is now 100
$x ??= 200 # $x remains 100
Operator trójskładnikowy
$true ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"
Nie ma potrzeby korzystania z rozszerzeń społeczności programu Powershell, można użyć standardowych instrukcji Powershell if jako wyrażenia:
variable = if (condition) { expr1 } else { expr2 }
A więc do zamienników dla twojego pierwszego wyrażenia w C #:
var s = myval ?? "new value";
staje się jedną z następujących (w zależności od preferencji):
$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }
lub w zależności od tego, co może zawierać $ myval, możesz użyć:
$s = if ($myval) { $myval } else { "new value" }
a drugie wyrażenie C # odwzorowuje w podobny sposób:
var x = myval == null ? "" : otherval;
staje się
$x = if ($myval -eq $null) { "" } else { $otherval }
Aby być uczciwym, nie są one zbyt zgryźliwe i nie są tak wygodne w użyciu, jak formularze C #.
Możesz również rozważyć zawinięcie go w bardzo prostą funkcję, aby uczynić rzeczy bardziej czytelnymi:
function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }
$s = Coalesce $myval "new value"
lub prawdopodobnie jako IfNull:
function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }
$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval
Jak widać, bardzo prosta funkcja zapewnia dużą swobodę składni.
AKTUALIZACJA: Jedną dodatkową opcją do rozważenia w miksie jest bardziej ogólna funkcja IsTrue:
function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }
$x = IfTrue ($myval -eq $null) "" $otherval
Następnie połącz to ze zdolnością Powershell do deklarowania aliasów, które wyglądają trochę jak operatory, a otrzymasz:
New-Alias "??" Coalesce
$s = ?? $myval "new value"
New-Alias "?:" IfTrue
$ans = ?: ($q -eq "meaning of life") 42 $otherval
Oczywiście nie wszystkim przypadnie do gustu, ale może być tym, czego szukasz.
Jak zauważa Thomas, jeszcze jedna subtelna różnica między wersją C # a wersją powyższą polega na tym, że C # dokonuje zwarcia argumentów, ale wersje programu Powershell obejmujące funkcje / aliasy zawsze będą oceniać wszystkie argumenty. Jeśli jest to problem, użyj if
formularza wyrażenia.
The variable '$myval' cannot be retrieved because it has not been set.
.
$myval = $null
przed wykonaniem testu, błąd powinien zniknąć.
$null -ne $a
Nie można teraz znaleźć przyzwoitego odniesienia, ale jest to długoletnia praktyka.
PowerShell 7 wprowadza wiele nowych funkcji i przeprowadza migrację z .NET Framework do .NET Core. Od połowy 2020 r. Nie zastąpił on całkowicie starszych wersji programu PowerShell ze względu na zależność od platformy .NET Core, ale firma Microsoft wskazała, że zamierza ostatecznie zastąpić starszą rodzinę Framework rodziny Core. Zanim to przeczytasz, kompatybilna wersja PowerShell może być już wstępnie zainstalowana w twoim systemie; jeśli nie, zobacz https://github.com/powershell/powershell .
Zgodnie z dokumentacją następujące operatory są obsługiwane natychmiast po wyjęciu z pudełka w programie PowerShell 7.0:
??
??=
... ? ... : ...
Działają tak, jak można by oczekiwać w przypadku koalescencji zerowej:
$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'
Ponieważ wprowadzono operator trójskładnikowy, możliwe są teraz następujące czynności, chociaż jest to niepotrzebne, biorąc pod uwagę dodanie zerowego operatora koalescencji:
$x = $a -eq $null ? $b : $a
Od wersji 7.0 dostępne są również następujące elementy, jeśli PSNullConditionalOperators
funkcja opcjonalna jest włączona , jak wyjaśniono w dokumentach ( 1 , 2 ):
?.
?[]
Mają kilka zastrzeżeń:
${}
jeśli następuje po nich jeden z operatorów eksperymentalnych, ponieważ znaki zapytania są dozwolone w nazwach zmiennych. Nie jest jasne, czy tak się stanie, jeśli / kiedy funkcje przejdą ze statusu eksperymentalnego (patrz numer 11379 ). Na przykład ${x}?.Test()
używa operatora new, ale $x?.Test()
działa Test()
na zmiennej o nazwie $x?
.?(
operatora, jak można by się spodziewać, jeśli pochodzisz z języka TypeScript. Poniższe nie będą działać:$x.Test?()
Wersje programu PowerShell wcześniejsze niż 7 mają rzeczywisty operator koalescencji wartości null lub przynajmniej operator, który jest zdolny do takiego zachowania. Tym operatorem jest -ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
Jest nieco bardziej wszechstronny niż operator łączący wartość null, ponieważ tworzy tablicę wszystkich elementów niezerowych:
$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
działa podobnie, co jest przydatne do liczenia pustych wpisów:
($null, 'a', $null -eq $null).Length
# Result:
2
Ale tak czy inaczej, oto typowy przypadek odzwierciedlenia ??
operatora C # :
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
To wyjaśnienie jest oparte na sugestii edycji od anonimowego użytkownika. Dzięki, kimkolwiek jesteś!
Na podstawie kolejności operacji działa to w następującej kolejności:
,
Operatora tworzy tablicą wartości, które mają być testowane.-ne
filtry operator żadnych elementów z tablicy, które pasują do podanych wartości - w tym przypadku, null. Wynikiem jest tablica wartości niezerowych w tej samej kolejności, co tablica utworzona w kroku 1.[0]
służy do zaznaczenia pierwszego elementu przefiltrowanej tablicy.Upraszczając, że:
W przeciwieństwie do operatora łączenia wartości null w języku C #, każde możliwe wyrażenie zostanie ocenione, ponieważ pierwszym krokiem jest utworzenie tablicy.
function DidItRun($a) { Write-Host "It ran with $a"; return $a }
i biegnij, ((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0]
aby to zobaczyć.
,
ma tak wysoki priorytet. Dla każdego, kto nie wie, jak to działa, ($null, 'alpha', 1 -ne $null)[0]
jest tak samo jak (($null, 'alpha', 1) -ne $null)[0]
. W rzeczywistości jedynymi dwoma operatorami „myślnikowymi” z wyższą precyzją są -split
i -join
(i jednoargumentowy myślnik? Tj. -4
Lub -'56'
).
To tylko połowa odpowiedzi na pierwszą połowę pytania, więc jedna czwarta odpowiedzi, jeśli wolisz, ale istnieje znacznie prostsza alternatywa dla operatora koalescencji zerowej, pod warunkiem, że domyślna wartość, której chcesz użyć, jest w rzeczywistości wartością domyślną dla typu :
string s = myval ?? "";
Można zapisać w Powershell jako:
([string]myval)
Lub
int d = myval ?? 0;
przekłada się na Powershell:
([int]myval)
Pierwszy z nich okazał się przydatny podczas przetwarzania elementu xml, który może nie istnieć i który, gdyby istniał, mógłby zawierać niepożądane białe znaki wokół niego:
$name = ([string]$row.td[0]).Trim()
Przelewanie na strunę zabezpiecza element przed zerowaniem i zapobiega ryzyku Trim()
awarii.
([string]$null)
-> ""
wygląda na "użyteczny, ale niefortunny efekt uboczny" :(
$null, $null, 3 | Select -First 1
zwroty
3
Jeśli zainstalujesz moduł rozszerzeń społeczności Powershell , możesz użyć:
?? jest aliasem dla Invoke-NullCoalescing.
$s = ?? {$myval} {"New Value"}
?: to alias dla Invoke-Ternary.
$x = ?: {$myval -eq $null} {""} {$otherval}
Wreszcie PowerShell 7 ma operatory przypisania 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
Często okazuje się, że podczas korzystania z koalescencji muszę również traktować pusty ciąg jako zerowy. Skończyło się na tym, że napisałem funkcję do tego, która używa rozwiązania Zenexera do łączenia w prostą koalescencję zerową, a następnie użyłem funkcji Keitha Hilla do sprawdzania wartości null lub pustej i dodałem ją jako flagę, aby moja funkcja mogła wykonywać oba te zadania.
Jedną z zalet tej funkcji jest to, że obsługuje ona również posiadanie wszystkich elementów null (lub pustych), bez zgłaszania wyjątku. Może być również używany do wielu dowolnych zmiennych wejściowych, dzięki temu, jak PowerShell obsługuje dane wejściowe tablic.
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)
}
}
Daje to następujące wyniki testów:
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
Kod testowy:
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)
Najbliższy, jaki mogę uzyskać, to: $Val = $MyVal |?? "Default Value"
Zaimplementowałem zerowy operator koalescencyjny dla powyższego w następujący sposób:
function NullCoalesc {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$Default
)
if ($Value) { $Value } else { $Default }
}
Set-Alias -Name "??" -Value NullCoalesc
Operator warunkowy trójskładnikowy można zaimplementować w podobny sposób.
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
I używane jak: $Val = $MyVal |?: $MyVal "Default Value"