PowerShell AST FindAll 方法采用带有 $args[0] 的脚本块

PowerShell AST FindAll method take a scriptblock with $args[0]

我一直在使用 PowerShell AST 为 PSScriptAnalyzer 创建一些自定义规则。

在很多AST的示例代码中,有一行我没看懂。这是一个例子。

首先解析一个文件,在本例中是 ISE 中当前打开的文件。

$AbstractSyntaxTree = [System.Management.Automation.Language.Parser]:: 
                  ParseInput($psISE.CurrentFile.Editor.Text, [ref]$null, [ref]$null)

到目前为止这是有道理的。假设我们要查找所有 ParameterAst 对象。下面是我看到的执行此操作的代码。

$params = $AbstractSyntaxTree.FindAll({$args[0] -is [System.Management.Automation.Language.ParameterAst]}, $true)

这行代码正在调用 FindAll 并传入一个脚本块,它似乎充当过滤器,因此只返回 ParameterAst 对象。

这里我不明白的是 $args[0] 如何适应这个调用。当调用 FindAll 方法时,任何参数实际上是如何传递到脚本块中的?

将脚本块视为匿名回调函数。

这和你使用 Where-Object { $someCondition } 时发生的事情是一样的。

.FindAll 找到所有的(事物)并且对于每一个它调用你提供的函数。它显然期待 [bool] 结果,并返回满足回调中存在的条件的对象。

在 powershell 的函数或脚本或脚本块中,您可以具有显式定义的命名参数,或者您可以 reference parameters without declaring them using the $args array,这就是此处发生的情况。

将脚本块用作回调类似于将其用于事件:

$Args

   Contains an array of the undeclared parameters and/or parameter
   values that are passed to a function, script, or script block.
   When you create a function, you can declare the parameters by using the
   param keyword or by adding a comma-separated list of parameters in
   parentheses after the function name.

   In an event action, the $Args variable contains objects that represent
   the event arguments of the event that is being processed.

FindAll 方法具有以下签名(来自 msdn):

public IEnumerable<Ast> FindAll (
    Func<Ast,bool> predicate,
    bool searchNestedScriptBlocks
)

所以第一个参数是一个委托,它将 Ast 作为输入,returns bool。 在 Powershell 中,您可以像这样创建这样的委托:

$delegate = { param($ast) $ast -is [System.Management.Automation.Language.ParameterAst] }

或不声明参数:

$delegate = { $args[0] -is [System.Management.Automation.Language.ParameterAst] }

FindAll 方法将执行类似的操作(伪代码):

foreach ($node in $allNodes) {
    $shouldAdd = & $delegate $node  <-- this is how $node gets passed to your delegate
    if ($shouldAdd) {
       <add the node to the output list>
    }
}