配列値を持つメンバーの追加


2

powershellクラス(ゲッターとセッターとも呼ばれるアクセサーとミューテーターを持たない)に問題があるため、add-memberを使用して作成されたカスタムオブジェクトを使用しているscriptblock。

シンプルなアイテムの場合、次のコードは正常に動作します

$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宣言にインデックスを含める方法がわからないため、これは期待どおりに機能しません。誰にもアイデアはありますか?

回答:


0

残念ながら、スクリプトのプロパティをパラメーター化する方法はありません。PowerShellのソースを読むことでこれを確認できます。内部的に、スクリプトプロパティのブックキーピングはPSScriptPropertyオブジェクトに保存されます。そのようなプロパティの値が要求または変更されると、プライベート関数InvokeGetterまたはInvokeSetterがそれぞれ呼び出されます。InvokeSetter新しい値を唯一の引数としてセッタースクリプトブロックを実行します(この抜粋の最後の行を参照)。

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

InvokeGetter 引数なしでゲッタースクリプトブロックを実行します。

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

したがって、追加情報をゲッターまたはセッターに渡すことはできません。(プロパティを設定しているオブジェクトscriptThisのみを参照し$thisます。)

回避策があります:パラメーターAdd-Type付きのコマンドレット-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

ご回答有難うございます。私はこれが事実だったのではないかと心配しましたが、あなたは長引く疑念を払拭するのに十分な証拠を提供しました。
TimN_FL
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.