Respostas:
O Powershell 7 apresenta coalescência nula nativa, atribuição condicional nula e operadores ternários no Powershell.
Null Coalescing
$null ?? 100 # Result is 100
"Evaluated" ?? (Expensive-Operation "Not Evaluated") # Right side here is not evaluated
Atribuição Condicional Nula
$x = $null
$x ??= 100 # $x is now 100
$x ??= 200 # $x remains 100
Operador Ternário
$true ? "this value returned" : "this expression not evaluated"
$false ? "this expression not evaluated" : "this value returned"
Não há necessidade de extensões da comunidade Powershell, você pode usar as instruções if padrão do Powershell como uma expressão:
variable = if (condition) { expr1 } else { expr2 }
Então, para as substituições de sua primeira expressão C # de:
var s = myval ?? "new value";
torna-se um dos seguintes (dependendo da preferência):
$s = if ($myval -eq $null) { "new value" } else { $myval }
$s = if ($myval -ne $null) { $myval } else { "new value" }
ou dependendo do que $ myval possa conter, você pode usar:
$s = if ($myval) { $myval } else { "new value" }
e a segunda expressão C # mapeia de maneira semelhante:
var x = myval == null ? "" : otherval;
torna-se
$x = if ($myval -eq $null) { "" } else { $otherval }
Agora, para ser justo, eles não são muito rápidos e nem de longe tão confortáveis de usar quanto os formulários C #.
Você também pode considerar envolvê-lo em uma função muito simples para tornar as coisas mais legíveis:
function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } }
$s = Coalesce $myval "new value"
ou possivelmente como, IfNull:
function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } }
$s = IfNull $myval "new value" $myval
$x = IfNull $myval "" $otherval
Como você pode ver, uma função muito simples pode fornecer um pouco de liberdade de sintaxe.
ATUALIZAÇÃO: uma opção extra a ser considerada na combinação é uma função IsTrue mais genérica:
function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } }
$x = IfTrue ($myval -eq $null) "" $otherval
Em seguida, combine isso é a capacidade do Powershell de declarar aliases que se parecem um pouco com operadores, você acaba com:
New-Alias "??" Coalesce
$s = ?? $myval "new value"
New-Alias "?:" IfTrue
$ans = ?: ($q -eq "meaning of life") 42 $otherval
É claro que isso não vai agradar a todos, mas pode ser o que você está procurando.
Como observa Thomas, uma outra diferença sutil entre a versão C # e a anterior é que o C # causa um curto-circuito nos argumentos, mas as versões do Powershell envolvendo funções / aliases sempre avaliarão todos os argumentos. Se isso for um problema, use a if
forma de expressão.
The variable '$myval' cannot be retrieved because it has not been set.
.
$myval = $null
antes de fazer o teste, o erro deve desaparecer.
$null -ne $a
Não é possível encontrar uma referência decente agora, mas é uma prática de longa data.
O PowerShell 7 apresenta muitos novos recursos e migra do .NET Framework para o .NET Core. Em meados de 2020, ele não substituiu completamente as versões legadas do PowerShell devido à dependência do .NET Core, mas a Microsoft indicou que pretende que a família Core eventualmente substitua a família Framework legada. No momento em que você lê isto, uma versão compatível do PowerShell pode vir pré-instalada em seu sistema; caso contrário, consulte https://github.com/powershell/powershell .
De acordo com a documentação , os seguintes operadores têm suporte imediato no PowerShell 7.0:
??
??=
... ? ... : ...
Funcionam como você esperaria para coalescência nula:
$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'
Uma vez que um operador ternário foi introduzido, o seguinte agora é possível, embora seja desnecessário devido à adição de um operador coalescente nulo:
$x = $a -eq $null ? $b : $a
A partir da versão 7.0, os itens a seguir também estarão disponíveis se o PSNullConditionalOperators
recurso opcional estiver ativado , conforme explicado nos documentos ( 1 , 2 ):
?.
?[]
Estes têm algumas ressalvas:
${}
se seguidas por um dos operadores experimentais porque pontos de interrogação são permitidos em nomes de variáveis. Não está claro se este será o caso se / quando os recursos passarem do status experimental (consulte a edição nº 11379 ). Por exemplo, ${x}?.Test()
usa o novo operador, mas $x?.Test()
é executado Test()
em uma variável chamada $x?
.?(
operador como você poderia esperar se você estiver vindo do TypeScript. O seguinte não funcionará:$x.Test?()
As versões do PowerShell anteriores a 7 têm um operador real de coalescência nula ou, pelo menos, um operador capaz de tal comportamento. Esse operador é -ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
É um pouco mais versátil do que um operador de coalescência nulo, pois cria uma matriz de todos os itens não nulos:
$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
funciona de forma semelhante, o que é útil para contar entradas nulas:
($null, 'a', $null -eq $null).Length
# Result:
2
Mas, de qualquer forma, aqui está um caso típico para espelhar o ??
operador C # :
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
Esta explicação é baseada em uma sugestão de edição de um usuário anônimo. Obrigado, seja você quem for!
Com base na ordem das operações, funciona na seguinte ordem:
,
operador cria uma matriz de valores a serem testados.-ne
operador filtra todos os itens da matriz que correspondem ao valor especificado - neste caso, nulo. O resultado é uma matriz de valores não nulos na mesma ordem da matriz criada na Etapa 1.[0]
é usado para selecionar o primeiro elemento da matriz filtrada.Simplificando isso:
Ao contrário do operador de coalescência nula do C #, todas as expressões possíveis serão avaliadas, pois a primeira etapa é criar uma matriz.
function DidItRun($a) { Write-Host "It ran with $a"; return $a }
e corra ((DidItRun $null), (DidItRun 'alpha'), 1 -ne $null)[0]
para ver isso.
,
tem uma precedência muito alta. Para quem está confuso sobre como isso funciona, ($null, 'alpha', 1 -ne $null)[0]
é o mesmo que (($null, 'alpha', 1) -ne $null)[0]
. Na verdade, os únicos dois operadores de "traço" com maior precedência são -split
e -join
(e traço unário? -4
Ou seja, ou -'56'
).
Esta é apenas meia resposta para a primeira metade da pergunta, portanto, um quarto de resposta se quiser, mas há uma alternativa muito mais simples para o operador de coalescência nula, desde que o valor padrão que você deseja usar seja na verdade o valor padrão para o tipo :
string s = myval ?? "";
Pode ser escrito no Powershell como:
([string]myval)
Ou
int d = myval ?? 0;
se traduz em PowerShell:
([int]myval)
Achei a primeira delas útil ao processar um elemento xml que pode não existir e que, se existisse, poderia ter um espaço em branco indesejado ao redor:
$name = ([string]$row.td[0]).Trim()
A conversão em string protege contra o elemento nulo e evita qualquer risco de Trim()
falha.
([string]$null)
-> ""
parece ser um "efeito colateral útil, mas infeliz" :(
$null, $null, 3 | Select -First 1
retorna
3
Se você instalar o Powershell Community Extensions Module , poderá usar:
?? é o alias de Invoke-NullCoalescing.
$s = ?? {$myval} {"New Value"}
?: é o alias de Invoke-Ternary.
$x = ?: {$myval -eq $null} {""} {$otherval}
Finalmente, o PowerShell 7 tem operadores de atribuição 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
Freqüentemente, acho que também preciso tratar string vazia como nula ao usar coalescer. Acabei escrevendo uma função para isso, que usa a solução de Zenexer para coalescer para a coalescência nula simples e, em seguida, usei a de Keith Hill para verificação de nulo ou vazio e adicionei isso como um sinalizador para que minha função pudesse fazer as duas coisas.
Uma das vantagens dessa função é que ela também lida com ter todos os elementos nulos (ou vazios), sem lançar uma exceção. Ele também pode ser usado para muitas variáveis de entrada arbitrárias, graças à forma como o PowerShell lida com entradas de array.
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)
}
}
Isso produz os seguintes resultados de teste:
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
Código de teste:
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)
O mais próximo que posso chegar é: $Val = $MyVal |?? "Default Value"
Implementei o operador de coalescência nulo para o acima assim:
function NullCoalesc {
param (
[Parameter(ValueFromPipeline=$true)]$Value,
[Parameter(Position=0)]$Default
)
if ($Value) { $Value } else { $Default }
}
Set-Alias -Name "??" -Value NullCoalesc
O operador ternário condicional pode ser implementado de maneira semelhante.
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
E usado como: $Val = $MyVal |?: $MyVal "Default Value"