检查PowerShell

时间:2018-05-24 09:14:51

标签: .net powershell ienumerable

如果IEnumerable为空,是否有原生PowerShell方法进行测试?

我知道我可以这样打电话给Linq.Enumerable.Any

[Linq.Enumerable]::Any($enumeration)

但我希望有一种更本土化的方式。

1 个答案:

答案 0 :(得分:1)

不幸的是,从Windows PowerShell v5.1 / PowerShell Core v6.1 开始,没有 PowerShell-native方式,而[Linq.Enumerable]::Any()至少是# These invocations 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)} 简洁,它可以在各种场景中打破

1.5
  • 现在,$null& {}[IEnumerable](评估为&#34; null集合&#34;)执行而非实施[System.Collections.IEnumerable]foreach或通用副本),但在PowerShell 的世界中,所有都是可枚举的,甚至标量,并且在中管道 - 但不是$null(!) - 偶然[System.Management.Automation.Internal.AutomationNull]::Value。值得注意的例外是&#34; null集合&#34; ([IEnumerable]),其唯一目的是表明没有没有进行枚举(因此你可以认为,作为一个特殊的枚举案例,应该< / em>实施1, 2, 3)。

  • 但是,[IEnumerable] 实现[object[]]:它是[object[]]类型的常规PowerShell数组;虽然你可以通过 - 一个明确的# 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 = try { $enumerable.ForEach({ Throw }); $False } catch { $True } 强制转换来解决这个特殊情况,但它显然不是一般解决方案,因为可能转换为数组强制完全枚举 - 请参阅底部更多信息。

一个强大但又繁琐的PowerShell原生功能解决方案可以处理上述所有情况(PSv4 +):

$enumerable

以上是:

  • 笨拙且难以记住。
  • 要求输入已存储在变量(上例中的[object[]])中。

但是,在PowerShell延迟评估的上下文中,通常来自直接调用 cmdlet 通过管道通过管道发送其输出对象 (换句话说,执行延迟评估的是PowerShell 管道),当您在中捕获输出时,该方面丢失变量,因为Powershell然后数组Test-Any)中静态收集输出。

因此,原生PowerShell解决方案 假设的 $True cmdlet

  • 逐个接收来自管道的输入。
  • 如果至少收到一个输入对象,则
  • 输出Test-Any

从Windows PowerShell v5.1 / PowerShell Core v6.1开始,无法停止按需管道Test-Any cmdlet需要执行此操作为了有效地工作(为了防止完全枚举):

  • 可以找到长期功能请求on GitHub

  • 可以在this answer中找到高效[Linq.Enumerable]::Any($enumerable)实施,该实施通过使用私有 PowerShell类型来解决限制问题。我的,PetSerAl的礼貌;除了依赖私有类型之外,您还会在会话中首次使用时产生按需编译性能损失。

可选阅读:1, 2, 3与PowerShell数组一起使用

@(1, 2, 3)(通常表示为[object[]],但这是不必要的)是.Any()数组的实例,PowerShell的默认数组类型。

我不清楚为什么你不能将这些数组传递给[Linq.Enumerable]::Any([object[]] (1,2,3)) # OK as-is ,因为它确实可以使用显式转换为相同类型[object[]]

收集命令的多对象输出也(隐式)创建一个[Linq.Enumerable]::Any((Get-ChildItem)) # OK数组,然而可以传递-is:$intArr = [int[]] (1, 2, 3); [Linq.Enumerable]::Any($intArr) # OK

最后,使用特定类型构造的数组也可以按原样传递:
[object[]]

如果有人知道为什么你不能在这种情况下使用直接构造的int数组,以及是否有充分的理由,请告诉我们。