Нулевое объединение в PowerShell

Существует ли нулевой коалесцирующий оператор в powershell?

Я хотел бы иметь возможность делать эти команды С# в powershell:

var s = myval ?? "new value";
var x = myval == null ? "" : otherval;

Ответ 1

Нет необходимости в расширениях Powershell Community, вы можете использовать стандартный оператор Powershell if в качестве выражения:

variable = if (condition) { expr1 } else { expr2 }

Итак, для замены вашего первого выражения на С#:

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" }

и второе выражение С# отображается аналогичным образом:

var x = myval == null ? "" : otherval;

становится

$x = if ($myval -eq $null) { "" } else { $otherval }

Теперь, чтобы быть справедливым, они не очень быстрые, и их далеко не так удобно использовать как формы С#.

Вы также можете обернуть его в очень простую функцию, чтобы сделать вещи более читабельными:

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

Очевидно, что это не всем понравится, но, возможно, это то, что вы ищете.

Как отмечает Томас, еще одно тонкое различие между версией С# и вышеизложенным состоит в том, что С# выполняет короткое замыкание аргументов, но версии Powershell, включающие функции/псевдонимы, всегда будут оценивать все аргументы. Если это проблема, используйте форму выражения if.

Ответ 2

Да, у PowerShell действительно есть оператор нулевой коалесценции или, по крайней мере, оператор, способный к такому поведению. Этот оператор -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

Но в любом случае здесь типичный случай, чтобы зеркально отобразить оператор С# ??:

'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output

Объяснение

Это объяснение основано на предложении редактирования от анонимного пользователя. Спасибо, кто бы вы ни были!

В зависимости от порядка операций это работает в следующем порядке:

  • Оператор , создает массив проверяемых значений.
  • Оператор -ne отфильтровывает любые элементы из массива, которые соответствуют указанному значению - в этом случае - null. Результатом является массив ненулевых значений в том же порядке, что и массив, созданный на шаге 1.
  • [0] используется для выбора первого элемента фильтрованного массива.

Упрощение этого:

  • Создайте массив возможных значений в предпочтительном порядке
  • Исключить все нулевые значения из массива
  • Возьмите первый элемент из результирующего массива

Предостережения

В отличие от оператора С# null коалесцирования, все возможные выражения будут оцениваться, так как первым шагом является создание массива.

Ответ 3

Это только половина ответа на первую половину вопроса, так что ежеквартальный ответ, если вы это сделаете, но есть намного более простая альтернатива нулевому коалесцирующему оператору, если значение по умолчанию, которое вы хотите использовать, фактически является значением по умолчанию для типа:

string s = myval ?? "";

Может быть написано в Powershell как:

([string]myval)

или

int d = myval ?? 0;

переводится в Powershell:

([int]myval)

Я нашел первое из них полезным при обработке элемента xml, который может не существовать и который, если он существует, может иметь нежелательные пробелы вокруг него:

$name = ([string]$row.td[0]).Trim()

Приведение в строчку защищает от элемента, равного нулю, и предотвращает потерю Trim().

Ответ 4

Если вы установите модуль расширения сообщества Powershell, вы можете использовать:

?? является псевдонимом для Invoke-NullCoalescing.

$s = ?? {$myval}  {"New Value"}

?: это псевдоним для Invoke-Ternary.

$x = ?: {$myval -eq $null} {""} {$otherval}

Ответ 5

$null, $null, 3 | Select -First 1

возвращает

3

Ответ 6

function coalesce {
   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = ($list -ne $null)
   $coalesced[0]
 }
 function coalesce_empty { #COALESCE for empty_strings

   Param ([string[]]$list)
   #$default = $list[-1]
   $coalesced = (($list -ne $null) -ne '')[0]
   $coalesced[0]
 }

Ответ 7

Часто я нахожу, что мне также нужно обрабатывать пустую строку как null при использовании coalesce. Я закончил тем, что написал для этого функцию, в которой используется Zenexer решение для объединения для простого нулевого объединения, а затем использовалось Keith Hill для проверки нуля или пустого места, и добавил, что в качестве флага, чтобы моя функция могла выполнять оба.

Одним из преимуществ этой функции является то, что она также обрабатывает все элементы null (или пустые) без исключения исключения. Он также может использоваться для произвольного множества входных переменных, благодаря тому, как 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)

Ответ 8

Самое близкое, что я могу получить: $Val = $MyVal |?? "Default Value" $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

Условный троичный оператор может быть реализован аналогичным образом.

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"