5

我目前正在尝试使用 PowerShell 3.0 中引入的 AST 功能来修改 ScriptBlock。我的要求是ScriptBlock的参数块中的所有参数都得到一个[Parameter(Mandatory)]属性。

基本上代码应该修改这个:

Param([string]$x)

Write-Host $x

对此:

Param([Parameter(Mandatory)][string]$x)

Write-Host $x

但是,我在添加新属性时遇到了一个问题,因为它需要一个IScriptExtent并且我不确定我应该如何创建一个新的IScriptExtent.

如何创建新的脚本范围?我可以为该职位使用什么值?我是否必须更改所有以下范围的位置?

我尝试只是重用我正在修改的每个参数的范围,但不幸的是,这似乎并没有产生它应该产生的结果(例如,当我调用ToString修改后的ScriptBlock我没有看到任何变化)。

到目前为止,我的实现是基于在此处ICustomAstVisitor找到的。

最重要的方法如下所示:

public object VisitParameter(ParameterAst parameterAst)
{
   var newName = VisitElement(parameterAst.Name);

   var extent = // What to do here?

   var mandatoryArg = new AttributeAst(extent, new ReflectionTypeName(typeof (ParameterAttribute)),
        new ExpressionAst[0],
        new[] {new NamedAttributeArgumentAst(extent, "Mandatory", new ConstantExpressionAst(extent, true), true)});

   var newAttributes = new[] {mandatoryArg}.Concat(VisitElements(parameterAst.Attributes));
   var newDefaultValue = VisitElement(parameterAst.DefaultValue);
      return new ParameterAst(parameterAst.Extent, newName, newAttributes, newDefaultValue);
}
4

2 回答 2

3

脚本范围主要用于错误报告,但也用于调试(例如,设置行断点。)

通常,合成脚本的选项(如您的示例)是:

  • 重用现有的 ast,可能与您正在添加的 ast 接近/相关
  • 使用空 ast(基本上创建没有文件、空行的 ScriptExtent 和 ScriptPosition 的实例)
  • 创建一个合成范围,以某种方式帮助调试,可能包含一些特殊内容

在您的示例中,上述任何一种都是合适的。第二个选项是最简单的。第三个选项只是第二个选项的变体,但您可以将内容设置为有用的内容,例如

<#Generated: [Parameter(Mandatory)] #>
于 2016-03-16T15:34:04.513 回答
3

以接口开头的名称I通常是接口。它们不是您创建实例的类,它们是指定特定类实现特定已知功能集的各种契约。

例如,一个[hashtable]实现IEnumerable. 这意味着任何知道如何使用IEnumerable接口并在该类上操作的东西;您可以创建自己的实现接口的类,并且永远不可能知道您的类或它的作用的代码仍然可以以IEnumerable定义的方式与它交互(在这种情况下,这是一种迭代它的方式)。

因此,当函数声明具有接口类型的参数时,它不是在寻找任何特定的类,而是在寻找实现该接口的任何类。

下一步是找出实现该接口的类型。这是我用来查找这些的一些 PowerShell 代码:

[System.AppDomain]::CurrentDomain.GetAssemblies().GetTypes() | Where-Object { 
    [System.Management.Automation.Language.IScriptExtent].IsAssignableFrom($_) 
}

由此,我们可以看到以下内容:

IsPublic IsSerial Name                                     BaseType                                                    
-------- -------- ----                                     --------                                                    
True     False    IScriptExtent                                                                                        
False    False    InternalScriptExtent                     System.Object                                               
False    False    EmptyScriptExtent                        System.Object                                               
True     False    ScriptExtent                             System.Object                                               

第一个清单是接口本身。其他三个中,有两个是不公开的,所以就离开了ScriptExtent

您可以创建其中之一,New-Object但您需要提供开始和结束位置作为[ScriptPosition]对象。在没有看到更多代码的情况下,我不完全确定那些应该是什么。

于 2016-03-14T18:34:16.183 回答