Answers:
Powershell 7在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社区扩展,可以使用标准的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
显然,这并不符合所有人的喜好,但可能正是您想要的。
正如Thomas所指出的那样,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年中,由于对.NET Core的依赖,它尚未完全替代PowerShell的旧版本,但微软表示,他们打算让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()
使用new运算符,但在名为的变量上$x?.Test()
运行Test()
$x?
。?(
如果您来自TypeScript,则没有您可能期望的运算符。以下内容无效:$x.Test?()
7之前的PowerShell版本确实具有实际的空合并运算符,或者至少具有能够实现这种行为的运算符。该运算符是-ne
:
# Format:
# ($a, $b, $c -ne $null)[0]
($null, 'alpha', 1 -ne $null)[0]
# Output:
alpha
它比null合并运算符更具通用性,因为它可以构成所有非null项的数组:
$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#的null合并运算符不同,由于第一步是创建数组,因此将评估每个可能的表达式。
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
or -'56'
)。
这只是问题前半部分的一半答案,如果可以的话,则为四分之一答案,但是如果您要使用的默认值实际上是该类型的默认值,则空合并运算符还有一个更简单的选择:
string s = myval ?? "";
可以用Powershell编写为:
([string]myval)
要么
int d = myval ?? 0;
转换为Powershell:
([int]myval)
我发现在处理一个可能不存在的xml元素时,其中的第一个很有用,如果确实存在,则可能在其周围带有多余的空格:
$name = ([string]$row.td[0]).Trim()
强制转换为字符串可防止元素为null并防止任何Trim()
失败的风险。
([string]$null)
-> ""
似乎是“有用的,但不幸的副作用” :(
如果安装Powershell社区扩展模块则可以使用:
?? 是Invoke-NullCoalescing的别名。
$s = ?? {$myval} {"New Value"}
?:是Invoke-Ternary的别名。
$x = ?: {$myval -eq $null} {""} {$otherval}
通常,我发现使用合并时还需要将空字符串视为null。我最终为此编写了一个函数,该函数使用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)
我能得到的最接近的是: $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"