Joh*_*van 6 powershell class yield-return
使用 PowerShell,历史上不需要yield return; 因为这就是管道的本质。但是,对于 PS5 的类,方法无法写入管道。因此,是否有任何选项可以从 Powershell 类方法中模仿yield return/pipeline行为?
此代码将数据返回到管道;我们可以看到变量 $global:i 被函数更新,然后在函数的下一次迭代之前,管道中的下一步读取该值:
[int]$i = 0
function Get-PowerShellProcesses() {
Get-Process | ?{$_.ProcessName -like '*powershell*'} | %{$global:i++; $_}
}
Get-PowerShellProcesses | %{"$i - $($_.ProcessName)}
Run Code Online (Sandbox Code Playgroud)
输出:
1 - powershell
2 - powershell_ise
Run Code Online (Sandbox Code Playgroud)
如果我们对一个类的方法做同样的事情,除了在传递到管道之前收集完整的结果集之外,一切都是一样的。
[int]$i = 0
class Demo {
Demo(){}
[PSObject[]]GetPowershellProcesses() {
return Get-Process | ?{$_.ProcessName -like '*powershell*'} | %{$Global:i++; $_}
}
}
$demo = New-Object Demo
$demo.GetPowerShellProcesses() | %{"$i - $($_.ProcessName)"}
Run Code Online (Sandbox Code Playgroud)
输出:
2 - powershell
2 - powershell_ise
Run Code Online (Sandbox Code Playgroud)
我猜没有解决办法;但希望有什么。
在上面的例子中显然不是。但是,这确实会影响我们不需要完整的结果集;例如,假设我们有一个| Select-Object -First 10after 函数调用,但有一个昂贵的操作返回数千个结果,我们会看到显着的性能下降。
Get-Process | ?{$_.ProcessName -like '*powershell*'} | %{return $_}
错误: Not all code path returns value within method.
Get-Process | ?{$_.ProcessName -like '*powershell*'} | %{return $_}
return
Run Code Online (Sandbox Code Playgroud)
错误: Invalid return statement within non-void method
[void]/$null返回:Get-Process | ?{$_.ProcessName -like '*powershell*'} | %{return $_}
return [void] #or return $null
Run Code Online (Sandbox Code Playgroud)
没有错误;但就像只调用了最后一个 return 语句一样;所以我们没有数据。
Get-Process | ?{$_.ProcessName -like '*powershell*'} | %{yield return $_}
错误: The term 'yield' is not recognized ...
简单的解决方法是将 C# 类与yield return或传统 PowerShell 函数一起使用。
SeeminglyScience 在 GitHub 上分享了这个问题的答案;一切都归功于他们。
您可以使用 LINQ 作为一种解决方法。以下是如何执行堆栈溢出示例。
using namespace System.Collections.Generic
using namespace System.Diagnostics
[int]$i = 0
class Demo {
[IEnumerable[Process]] GetPowershellProcesses() {
return [Linq.Enumerable]::Select(
[Process[]](Get-Process *powershell*),
[Func[Process, Process]]{ param($p) $global:i++; $p })
}
}
$demo = New-Object Demo
$demo.GetPowerShellProcesses() | %{ "$i - $($_.ProcessName)" }
Run Code Online (Sandbox Code Playgroud)
但是,该范围内的变量可能可用也可能不可用,具体取决于创建可枚举的 SessionStateScope 在枚举期间是否仍处于活动状态。在 PowerShell 中使用脚本块当前工作方式实现任何产量时,这也可能是一个问题。
| 归档时间: |
|
| 查看次数: |
2536 次 |
| 最近记录: |