Відповіді:
Powershell 7 вводить в "Powershell" нативну нульову злиття, нульове умовне призначення та потрійні оператори.
Null Coalescing
$null ?? 100 # Result is 100
"Evaluated" ?? (Expensive-Operation "Not Evaluated") # Right side here is not evaluated
Нульове умовне призначення
$x = $null
$x ??= 100 # $x is now 100
$x ??= 200 # $x remains 100
Термінальний оператор
$true ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"
Немає потреби в розширеннях Powershell Community, ви можете використовувати стандартний Powershell, якщо заяви як вираз:
variable = if (condition) { expr1 } else { expr2 }
Отже, до замін для першого C # вираження:
var s = myval ?? "new value";
стає одним із наступних (залежно від уподобань):
$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }
або залежно від того, що може містити $ myval:
$s = if ($myval) { $myval } else { "new value" }
і другий C # вираз відображається аналогічно:
var x = myval == null ? "" : otherval;
стає
$x = if ($myval -eq $null) { "" } else { $otherval }
Тепер, якщо чесно, вони не дуже спритні, і ніде не зручні у використанні, як форми C #.
Ви також можете розглянути можливість його перетворення в дуже просту функцію, щоб зробити речі більш читаними:
function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }
$s = Coalesce $myval "new value"
або, можливо, як IfNull:
function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }
$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval
Як ви бачите, дуже проста функція може дати вам трохи свободи синтаксису.
ОНОВЛЕННЯ: Один додатковий варіант, який слід врахувати в суміші, - це більш загальна функція IsTrue:
function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }
$x = IfTrue ($myval -eq $null) "" $otherval
Потім поєднайте, що є здатністю Powershell оголошувати псевдоніми, схожі на операторів, ви закінчуєте:
New-Alias "??" Coalesce
$s = ?? $myval "new value"
New-Alias "?:" IfTrue
$ans = ?: ($q -eq "meaning of life") 42 $otherval
Ясна річ, це не буде до смаку кожному, але, можливо, те, що ви шукаєте.
Як зазначає Томас, одна інша тонка різниця між версією C # і вищезгаданим полягає в тому, що C # виконує коротке замикання аргументів, але версії Powershell, що включають функції / псевдоніми, завжди будуть оцінювати всі аргументи. Якщо це проблема, використовуйте if
форму вираження.
The variable '$myval' cannot be retrieved because it has not been set.
.
$myval = $null
перед тестом, помилка повинна усунутись.
$null -ne $a
не можу знайти гідного посилання, але це давня практика.
PowerShell 7 представляє багато нових функцій і переходить з .NET Framework в .NET Core. Станом на середину 2020 року, він не повністю замінив застарілі версії PowerShell через залежність від .NET Core, але Microsoft заявила, що вони мають намір сімейство Core врешті-решт замінити спадщину сімейства Framework. До того часу, коли ви прочитаєте це, у вашій системі може бути попередньо встановлена сумісна версія PowerShell; якщо ні, дивіться https://github.com/powershell/powershell .
Згідно з документацією , в PowerShell 7.0 підтримуються такі оператори:
??
??=
... ? ... : ...
Вони працюють так, як ви очікували при нульовому поєднанні:
$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'
З моменту введення потрійного оператора, тепер можливе наступне, хоча це зайве з огляду на додавання оператора зведення нуля:
$x = $a -eq $null ? $b : $a
Станом на 7.0 також доступні наступні, якщо включенаPSNullConditionalOperators
додаткова функція , як пояснено в документах ( 1 , 2 ):
?.
?[]
У них є кілька застережень:
${}
якщо за ними слідує один з експериментальних операторів, оскільки знаки запитання дозволені у назвах змінних. Незрозуміло, чи буде це так, якщо / коли функції закінчать експериментальний статус (див. Випуск № 11379 ). Наприклад, ${x}?.Test()
використовує нового оператора, але $x?.Test()
працює Test()
на змінній з назвою $x?
.?(
оператора, як ви могли очікувати, якщо ви приїжджаєте з TypeScript. Наступне не працює:$x.Test?()
Версії PowerShell до 7 мають дійсний оператор з’єднання нуля або, принаймні, оператора, здатного до такої поведінки. Цей оператор -ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
Це трохи більш універсально, ніж оператор зведення нуля, оскільки він створює масив усіх ненульових елементів:
$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
працює аналогічно, що корисно для підрахунку нульових записів:
($null, 'a', $null -eq $null).Length
# Result:
2
Але все одно, ось типовий випадок дзеркального відображення ??
оператора C # :
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
Це пояснення базується на пропозиції щодо редагування анонімного користувача. Дякую, хто б ти не був!
Виходячи з порядку операцій, це працює в наступному порядку:
,
Оператор створює масив значень для тестування.-ne
операторському відфільтровує будь-які елементи з масиву , які відповідають вказаним значенням - в даному випадку, нульовий. Результатом є масив ненульових значень у тому ж порядку, що і масив, створений на етапі 1.[0]
використовується для вибору першого елемента відфільтрованого масиву.Спрощення цього:
На відміну від оператора з нульовим злиттям C #, кожне можливе вираження буде оцінено, оскільки перший крок - це створення масиву.
function DidItRun($a) { Write-Host "It ran with $a"; return $a }
і запустіть, ((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0]
щоб побачити це.
,
має такий високий пріоритет. Для тих, хто плутається в тому, як це працює, ($null, 'alpha', 1 -ne $null)[0]
те саме, що (($null, 'alpha', 1) -ne $null)[0]
. Насправді єдиними двома "тире" операторами з більш високим пріоритетом є -split
і -join
(і одинарний тире? Тобто. -4
Або -'56'
).
Це лише половина відповіді на першу половину запитання, тож відповідь на чверть, якщо ви хочете, але є набагато простіша альтернатива оператору зсуву нуля за умови, що значення за замовчуванням, яке ви хочете використовувати, є фактично значенням за замовчуванням для типу :
string s = myval ?? "";
Можна написати в Powershell як:
([string]myval)
Або
int d = myval ?? 0;
перекладає на Powershell:
([int]myval)
Я знайшов перший з них корисним при обробці елемента XML, який може не існувати, і який, якщо він існує, міг би мати небажаний пробіл навколо нього:
$name = ([string]$row.td[0]).Trim()
Передача на рядок захищає від недійсності елемента та запобігає будь-якому ризику Trim()
відмови.
([string]$null)
-> ""
здається "корисним, але невдалим побічним ефектом" :(
$null, $null, 3 | Select -First 1
повертає
3
Якщо ви встановите модуль розширень Powershell Community, ви можете використовувати:
?? є псевдонімом Invoke-NullCoalescing.
$s = ?? {$myval} {"New Value"}
?: псевдонім для Invoke-Ternary.
$x = ?: {$myval -eq $null} {""} {$otherval}
Нарешті, PowerShell 7 отримав операторів призначення 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
Часто я виявляю, що мені також потрібно вважати порожню рядок як нульовою при використанні coalesce. Я закінчив написати для цього функцію, яка використовує рішення Zenexer для з’єднання для простого нульового зрощення, а потім використала Keith Hill для нульової чи порожньої перевірки, і додала, що як прапор, щоб моя функція могла виконувати і те, і інше.
Однією з переваг цієї функції є те, що вона також обробляє всі елементи нульовими (або порожніми), не кидаючи виняток. Його також можна використовувати для довільних безлічі вхідних змінних, завдяки тому, як PowerShell обробляє вхід масиву.
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)
}
}
Це дає такі результати тесту:
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
Код тесту:
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)
Найближче, що я можу отримати: $Val = $MyVal |?? "Default Value"
Я реалізував оператор null coalescing для описаного вище:
function NullCoalesc {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$Default
)
if ($Value) { $Value } else { $Default }
}
Set-Alias -Name "??" -Value NullCoalesc
Умовна потрійна оператор може бути реалізована в Similary чином.
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
І використовується як: $Val = $MyVal |?: $MyVal "Default Value"