在PowerShell中的空值合并

32 浏览
0 Comments

在PowerShell中的空值合并

在PowerShell中是否有空值合并运算符?

我希望能够在PowerShell中执行以下C#命令:

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

admin 更改状态以发布 2023年5月21日
0
0 Comments

PowerShell 7及以上版本

PowerShell 7推出了许多新功能并迁移到了.NET Core。截至2020年中期,它尚未完全取代由于依赖.NET Core而存在的旧版PowerShell,但微软已表示他们打算最终用核心系列替换旧的框架系列。当您阅读此文时,您的系统上可能预装了PowerShell的兼容版本;如果没有,请参见https://github.com/powershell/powershell

根据文档,以下运算符在PowerShell 7.0中直接支持:

  1. Null-合并??
  2. Null-合并赋值??=
  3. 三元... ? ... : ...

这些运算符的使用方式与您所期望的Null-合并相同:

$x = $a ?? $b ?? $c ?? 'default value'
$y ??= 'default value'

由于已经引入了三元运算符,以下是现在可能的,但由于已添加了Null-合并运算符,这是不必要的:

$x = $a -eq $null ? $b : $a

自7.0以来,如果启用了可选特性PSNullConditionalOperators,还可以使用以下内容,如文档所述1, 2):

  1. 成员的空条件访问: ?.
  2. 数组等的空条件访问: ?[]

这些具有一些警告:

  1. 由于这些是实验性的,它们可能会发生变化。当您阅读本文时,它们可能已不再是实验性的,并且警告列表可能已更改。
  2. 如果后面跟着实验性运算符,则变量必须用${}括起来,因为变量名允许问号。如果/当这些特性毕业时,不清楚是否会是这种情况(请参见issue#11379)。例如,${x}?.Test()使用新运算符,但$x?.Test()在一个名为$x?的变量上运行Test()
  3. 没有

    运算符,如果您来自TypeScript,您可能会期望。以下功能不起作用:$x.Test?()

PowerShell 6及更早版本

在PowerShell 7之前的PowerShell版本确实具有一个实际的Null-合并运算符,或者至少具有这种行为的运算符。该运算符为-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

说明

这篇说明是基于一个匿名用户的编辑建议。谢谢你,不知名的好心人!

按照操作顺序,该方法按以下步骤进行:

  1. , 运算符创建一个要测试的值数组。
  2. -ne 运算符从数组中过滤出任何与指定值(这里是 null)匹配的项目。结果是按照步骤 1 中创建的数组顺序的非空值数组。
  3. 使用 [0] 选择过滤后数组的第一个元素。

简单来说:

  1. 创建一个可能值的数组,按照首选顺序
  2. 从数组中排除所有 null 值
  3. 从生成的数组中选择第一个项目

注意事项

与 C# 的空合并运算符不同,因为第一步是创建一个数组,所以会评估每个可能的表达式。

0
0 Comments

Powershell 7+

Powershell 7 引入了本地的空合并、空条件赋值和三元运算符。

空合并

$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

显然,这不会适合每个人的口味,但可能是您正在寻找的。

正如 Thomas 指出的另一个微妙之处,C# 版本和上述版本之间的另一个不同之处是 C# 对参数执行短路计算,但涉及函数/别名的 Powershell 版本将始终评估所有参数。如果这是一个问题,请使用 if 表达式形式。

0