PowerShell Where-Object 与 Where 方法 [英] PowerShell Where-Object vs. Where method

查看:66
本文介绍了PowerShell Where-Object 与 Where 方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到写 PowerShell 类行时发生的一件有趣而奇怪的事情:

An interesting and weird thing I noticed writing PowerShell classes lines:

class A {

    [object] WhereObject(){
        return @(1,2) | Where-Object {$_ -gt 2}
    }

    [object] Where(){
        return @(1,2).Where( {$_ -gt 2})
    }
}

$a = new-object A
$a.WhereObject() # Throw exception Index was out of range. Must be non-negative and less than the size of the collection.

$a.Where() # Works well

看起来像是设计使然.为什么会这样?

It looks like it is by design. Why does it work so?

解决方法

将空"值显式转换为 $null 的函数:

Function which explicitly convert "empty" value to $null:

function Get-NullIfEmpty {
   param(
       [Parameter(ValueFromPipeline=$true)][array] $CollectionOrEmtpy
   )

   begin { $output = $null }

   process
   {
      if($output -eq $null -and $CollectionOrEmtpy -ne $null){
          $output = @()
      }
      foreach ($element in $CollectionOrEmtpy)
      {
          $output += $element
      }
   }

   end { return $output }
}

在这种情况下,该方法将如下所示:

In this case, the method will look like:

[object] WhereObject() {
   return @(1,2) | Where-Object {$_ -gt 2} | Get-NullIfEmpty
}

我试图从类方法返回一个空数组,但这也很棘手,因为对于常规函数,空数组也意味着无".如果您有像 method1 -> function -> method2 - method1 这样的调用链,则会抛出相同的异常.因为函数将空数组转换为空数组.

I tried to return an empty array from the class method, but it is also tricky because for a regular function an empty array means "nothing" as well. If you have a call chain like method1 -> function -> method2 - method1 throw the same exception. Because the function converts an empty array to nothing.

所以在我的情况下转换为 $null 是最佳的 :)

So converting to $null is optimal in my case :)

推荐答案

  • (PowerShell v4+).Where() 方法,在表达式模式总是返回一个[System.Collections.ObjectModel.Collection[psobject]]的实例:

    • The (PowerShell v4+) .Where() method, which is evaluated in expression mode, always returns an instance of [System.Collections.ObjectModel.Collection[psobject]]:

      • 如果没有匹配的输入对象,则该实例只是(它没有元素并且它的 .Count 属性返回 0).
      • If no input objects match, that instance is simply empty (it has no elements and its .Count property returns 0).

      相比之下,Where-Object cmdlet 使用管道语义,这意味着以下内容输出行为:

      By contrast, the Where-Object cmdlet uses pipeline semantics, which implies the following output behavior:

      • 如果输出 nothing(如果没有与过滤器脚本块匹配的内容),则返回值是空集合",这在技术上是 [System.Management.Automation.Internal.AutomationNull]::Value 单例.

      • If nothing is output (if nothing matches the filter script block), the return value is a "null collection", which is technically the [System.Management.Automation.Internal.AutomationNull]::Value singleton.

      如果单个项目匹配,则该项目按原样输出.

      If a single item matches, that item is output as-is.

      如果多个项匹配并且它们被收集在一个变量中/作为表达式的一部分进行评估,它们被收集在一个[object[]]数组中.

      If multiple items match and they are collected in a variable / evaluated as part of an expression, they are collected in an [object[]] array.

      至于具体症状 - 其中 Bruce Payette 的回答 已经确认是一个错误.

      As for the specific symptom - which Bruce Payette's answer has since confirmed to be a bug.

      • 更新:该错误至少从 v7 开始修复;返回无"(AutomationNull) 现在被强制为 $null;查看原始 GitHub 上的错误报告.
      • Update: The bug is fixed since at least v7; returning "nothing" (AutomationNull) is now coerced to $null; see the original bug report on GitHub.

      内部 [List[object]] 实例用于收集方法调用的输出,通过内部管道执行.如果该内部管道输出无"- 即,[System.Management.Automation.Internal.AutomationNull]::Value - 没有 对象被添加到列表中.但是,后续代码假设列表中至少有一个对象,并盲目访问索引0,导致手头的错误.

      An internal [List[object]] instance is used to collect the method call's output, executed via an internal pipeline. If that internal pipeline outputs "nothing" - i.e., [System.Management.Automation.Internal.AutomationNull]::Value - no object is added to the list. However, subsequent code assumes that there is at least one object in the list and blindly accesses index 0, causing the error at hand.

      问题的更简单再现:

      class A {
        # Try to return [System.Management.Automation.Internal.AutomationNull]::Value
        # (which is what `& {}` produces).
        [object] WhereObject(){ return & {} }
      }
      
      $a = new-object A
      
      $a.WhereObject() # Throw exception Index was out of range. Must be non-negative and less than the size of the collection.
      

      至于理想的行为:

      如果方法的代码返回null 集合",此修复似乎将导致 $null 获得输出,使用 C# 的默认值功能 - 参见 此评论.

      It seems that the fix will result in $null getting output if the method's code returns the "null collection", using C#'s default-value feature - see this comment.

      这篇关于PowerShell Where-Object 与 Where 方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆