Ответы:
Powershell 7 представляет встроенное объединение null, условное присвоение null и тернарные операторы в Powershell.
Нулевое слияние
$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 Extensions не требуются, вы можете использовать стандартные операторы Powershell if в качестве выражения:
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 ):
?.
?[]
У них есть несколько предостережений:
${}
if, за которым следует один из экспериментальных операторов, поскольку в именах переменных разрешены вопросительные знаки. Неясно, будет ли это так, если / когда функции выйдут из экспериментального статуса (см. Проблему № 11379 ). Например, ${x}?.Test()
использует оператор new, но $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]
используется для выбора первого элемента фильтруемого массива.Упрощая это:
В отличие от оператора объединения NULL в 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
and -join
(и унарное тире? Т.е. -4
или -'56'
).
Это только половина ответа на первую половину вопроса, поэтому четвертый ответ, если хотите, но есть гораздо более простая альтернатива оператору объединения null при условии, что значение по умолчанию, которое вы хотите использовать, на самом деле является значением по умолчанию для типа :
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, вы можете использовать:
?? это псевдоним для 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
@($null,$null,"val1","val2",5) | select -First 1
Часто я обнаруживаю, что мне также нужно рассматривать пустую строку как нулевую при использовании coalesce. В итоге я написал функцию для этого, которая использует решение Zenexer для объединения для простого объединения NULL, а затем использовал 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"
Я реализовал нулевой оператор объединения для вышеуказанного следующим образом:
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"