使用数组值添加成员

使用数组值添加成员

由于我在使用 powershell 类时遇到的问题(没有访问器和修改器,又名 getter 和 setter),我一直在使用通过 add-member 创建的自定义对象,因此在确定在 SecondValue 脚本块中引用数组值的正确方法时遇到了问题。

对于简单的项目,以下代码可以正常工作

$Object = New-Object PSObject
Add-Member -InputObject $Object -MemberType NoteProperty -Name "Array" -Value @() -Force
$Object.Array += 1
$Object.Array
$Object.Array[0] = 2

但是因为我想要在设置值时添加选项(参数验证,设置其他相关属性),所以我一直使用以下格式

$Object2 = New-Object PSObject
Add-Member -InputObject $Object2 -MemberType ScriptProperty -Name "Array" -Value {@($this.ArrayData)} -SecondValue{
    param($NewValue)
    $this.ArrayData = $NewValue}
Add-Member -InputObject $Object2 -MemberType NoteProperty -Name "ArrayData" -Value @() -Force

这没有按预期工作,因为我不知道如何在 SecondValue 声明中包含索引。有人有什么想法吗?

答案1

不幸的是,没有办法参数化脚本属性。我们可以通过阅读 PowerShell 源代码来验证这一点。在内部,脚本属性的记录存储在PSScriptProperty对象。当请求或更改此类属性的值时,将分别调用私有函数InvokeGetter或。InvokeSetterInvokeSetter运行 setter 脚本块,以新值作为唯一参数(如此摘录的最后一行所示):

SetterScript.DoInvokeReturnAsIs(
    useLocalScope: true,
    errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe,
    dollarUnder: AutomationNull.Value,
    input: AutomationNull.Value,
    scriptThis: scriptThis,
    args: new object[] { value });

InvokeGetter运行不带任何参数的 getter 脚本块:

return GetterScript.DoInvokeReturnAsIs(
    useLocalScope: true,
    errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.SwallowErrors,
    dollarUnder: AutomationNull.Value,
    input: AutomationNull.Value,
    scriptThis: scriptThis,
    args: Utils.EmptyArray<object>());

因此,我们不能向 getter 或 setter 传递任何额外信息。(scriptThis仅指$this我们正在设置属性的对象。)

有一个解决方法:Add-Typecmdlet 参数-TypeDefinition。您可以嵌入一些 C#(或 VB.NET,如果您愿意)代码来定义可转位型

Add-Type -TypeDefinition @"
using System;
using System.Runtime.CompilerServices;
public class SomeClass {
    private int[] myArray;
    public SomeClass(int Capacity) {
        myArray = new int[Capacity];
    }
    [IndexerName("ArrayData")] public int this[int index] {
        get {
            Console.WriteLine("Somebody asked for the element at index " + index.ToString() + "!");
            return myArray[index];
        }
        set {
            if (value < 0) throw new InvalidOperationException("Negative numbers not allowed");
            if (index == 0) throw new InvalidOperationException("The first element cannot be changed");
            myArray[index] = value;
        }
    }
}
"@

然后你可以做这样的事情:

$obj = [SomeClass]::new(5)
$obj[3] = 255
Write-Host $obj[3] # Prints the "somebody accessed" notice, then 255

或者您可以利用索引器名称并执行以下操作:

$obj.ArrayData(3) = 255 # Note the parentheses, not brackets
Write-Host $obj.ArrayData(3) # Prints the notice, then 255

相关内容