很遗憾,有noWindows PowerShell 中的 PowerShell 原生方式/自 PowerShell (Core) v7.2 起,同时[Linq.Enumerable]::Any()
至少是concise, 它可以break在各种场景和不懒惰地操作在 PowerShell 中:
# These invocations with various *PowerShell* enumerables all FAIL with
# 'Cannot find an overload for "Any" and the argument count: "1"'
foreach ($enumerable in 1.5, $null, (& {}), (1,2,3)) {
[Linq.Enumerable]::Any($enumerable) # !! BREAKS
}
# However, it does work with arrays that are *explicitly typed*.
[Linq.Enumerable]::Any([int[]] (1, 2)) # -> $true
-
Now, 1.5
, $null
and & {}
do not实施[IEnumerable]
([System.Collections.IEnumerable]
或通用对应物),但是在 PowerShell 的世界里一切是可枚举的, even scalars and $null
,但后者仅在pipeline,不与foreach
。值得注意的例外是“collection null”值,又名“AutomationNull”,其唯一目的是表明存在nothing枚举(因此你可以认为,作为一种特殊的枚举情况,它should实施[IEnumerable]
) - see 这个答案.
-
然而,1, 2, 3
does实施[IEnumerable]
:它是一个常规的 PowerShell 数组类型[object[]]
;虽然你可以用 - 奇怪的是 - 显式解决这个特殊情况[object[]]
强制转换,这显然不是一个通用的解决方案,因为有可能转换为array强制完整枚举 - 请参阅底部部分以获取更多信息。
-
未来将更好的 LINQ 集成到 PowerShell 中是主题GitHub 问题 #2226.
一个强大但晦涩且非懒惰的仅 PowerShell 原生功能的解决方案处理上述所有情况的方法是(PSv4+):
# Returns $true if $enumerable results in enumeration of at least 1 element.
# Note that $null is NOT considered enumerable in this case, unlike
# when you use `$null | ...`
$haveAny = $enumerable.Where({ $true }, 'First').Count -ne 0
# Variant with an example of a *filter*
# (Find the first element that matches a criterion; $_ is the object at hand).
$haveAny = $enumerable.Where({ $_ -gt 1000 }, 'First').Count -ne 0
以上是:
- 不太明显,因此很难记住。
- 更重要的是,这种方法不能利用pipeline,这就是 PowerShell 的实现方式惰性(按需)枚举, and 此限制适用于all .NET 方法调用, 包括
[Linq.Enumerable]::Any()
.
也就是说,可枚举 - 因为method正在被召唤 - 必须是表达,并且当 PowerShell 使用命令作为表达式(包括分配给变量)时,它运行命令直至完成并且隐含地收集所有输出 in an [object[]]
- 类型数组。
因此,一个lazy本机 PowerShell 解决方案需要使用pipeline,形式为a 假想 Test-Any
cmdlet, which:
- 通过接收输入pipeline, in a 流媒体时尚(逐个对象)。
- outputs
$true
如果接收到至少一个输入对象。
Note: The examples use $enumerable
as pipeline input for brevity, but only with actual calls to PowerShell commands, say , Get-ChildItem, would you get streaming (lazy) behavior.
# WISHFUL THINKING
$haveAny = $enumerable | Test-Any
# Variant with filter.
$haveAny = $enumerable | Test-Any { $_ -gt 100 }
The 无条件的(无过滤器)变体Test-Any
可以通过有效地模拟Select-Object -First 1
$haveAny = 1 -eq ($enumerable | Select-Object -First 1).Count
Select-Object
可以利用异常类型来短路管道输入private在 Windows PowerShell 和 PowerShell (Core) v7.2 中。也就是说,有目前用户代码无法按需停止管道,其中Test-Any
cmdlet 需要执行以下操作才能有效工作(以防止完全枚举):
-
可以找到长期存在的功能请求在 GitHub 问题 #3821 中.
-
An 高效、懒惰Test-Any
通过使用来解决该限制的实现privatePowerShell类型可以在这个答案,礼貌地PetSerAl;除了依赖私有类型之外,您还会遭受按需编译性能损失first在会话中使用。
-
与此相类似,GitHub 问题 #13834要求.Where()数组法的高级功能被引入其基于管道的等效项,Where-Objectcmdlet(其内置别名是where
),这将允许一个解决方案,例如:
# WISHFUL THINKING
$haveAny = 1 -eq ($enumerable | where { $_ -gt 1000 } -First).Count
可选阅读:使用[Linq.Enumerable]::Any($enumerable)
使用 PowerShell 数组
1, 2, 3
(通常表示为@(1, 2, 3)
,但是这是不必要的)是一个实例[object[]]
array,PowerShell 的默认数组类型。
我不清楚为什么你不能将这样的数组传递给.Any()
as-is,鉴于它确实可以与显式强制转换一起使用同类型: [Linq.Enumerable]::Any([object[]] (1,2,3)) # OK
最后,用一个构造的数组specific类型也可以按原样传递:
$intArr = [int[]] (1, 2, 3); [Linq.Enumerable]::Any($intArr) # OK
如果有人知道为什么你不能使用[object[]]
在此上下文中的数组没有明确的强制转换是否有充分的理由,请告诉我们。