Powershell 对管道对象调用方法

Powershell 对管道对象调用方法,powershell,methods,pipeline,Powershell,Methods,Pipeline,最好有一个PS过滤器来调用方法,例如 [System.Text.Encoding]::UTF8.GetString 使以下事情成为可能: filter Invoke-Method { ... ?? ... } Invoke-WebRequest $url ` | Select-Object Content ` | Invoke-Method [System.Text.Encoding]::UTF8.GetString 是成员调用的示例,但我尝试为我的案例构造类似的内容时失败了

最好有一个PS过滤器来调用方法,例如

[System.Text.Encoding]::UTF8.GetString

使以下事情成为可能:

filter Invoke-Method { ... ?? ... }

Invoke-WebRequest $url `
    | Select-Object Content `
    | Invoke-Method [System.Text.Encoding]::UTF8.GetString

是成员调用的示例,但我尝试为我的案例构造类似的内容时失败了。

如果输入对象键入正确,则是:

filter Invoke-Method {
  param(
    [System.Management.Automation.PSMethod]
    $Method
  )

  return $Method.Invoke($_)
}

(65..74 -as [byte[]]) |Invoke-Method -Method ([System.Text.Encoding]::UTF8.GetString)
为您提出的问题提供优雅的解决方案

但是,方法仅限于传递一个静态方法,将手头的管道对象传递给该方法,而PowerShell确实有一个内置的灵活的每管道输入处理命令:cmdlet,其内置别名为
%
,向其传递脚本块(
{…}
)其中,
$\uu
指的是手头的管道输入对象):

请注意,为了将表示UTF8编码文本的字节数组转换回字符串,必须通过管道将其作为一个整体发送,这是一元数组构造操作符
在此实现的(它将字节数组包装在助手数组中,在管道中枚举时,助手数组将字节数组作为一个整体发送)

如果调用的方法是每个管道输入对象的成员,那么事情在语法上就变得更容易了,在这种情况下,您可以使用操作语句(PSv3+):

有关详细信息,请参阅


性能注意事项

从PowerShell Core 6.2.0开始编写

令人惊讶的是,操作语句(尽管不涉及脚本块)比等效的脚本块语法慢; e、 例如,
'foo',bar'|%ToUpper
'foo',bar'|%{$.ToUpper()}

定义一个过滤函数是目前为止最快的
,但是,如上所述,它仅限于静态方法(如果您通过脚本块或使用反射通过
.psobject.methods
通过成员名传递操作来执行,那么速度优势将变成相反的结果)

但是,如果性能至关重要,并且确实需要对每个输入对象调用方法,则可以使用硬编码的方法调用定义筛选函数:

filter ToUpper { $_.ToUpper() }
'foo', 'bar' | ToUpper  # much faster than: 'foo', 'bar' | % ToUpper

一个优雅的解决方案,在OP的场景中运行良好,甚至比
。|%{[System.Text.Encoding]::UTF8.GetString($)}
;然而,它通常只是一个带有静态方法的选项(至少具有合理的性能)。作为旁白:我建议将字节数组作为一个整体传递给方法;UTF8单独解码字节是无意义的(ASCII范围内的代码点除外)。
# Call the .ToUpper() method on each input string:
PS> 'foo', 'bar' | % ToUpper # short for: 'foo', 'bar' | % { $_.ToUpper() }
FOO
BAR
filter ToUpper { $_.ToUpper() }
'foo', 'bar' | ToUpper  # much faster than: 'foo', 'bar' | % ToUpper