Add-Member com valor de Array

2

Devido a problemas que tenho com classes powershell (não tendo accessors e mutators aka getter e setters), tenho usado objetos personalizados criados usando add-member Estou tendo um problema com descobrir o caminho certo para fazer referência a valores de matriz no script script SecondValue.

Para itens simples, o código a seguir funciona bem

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

Mas porque eu quero opções de adição (validação de parâmetro, configurações de propriedades adicionais relacionadas) ao definir o valor que eu tenho usado o seguinte formato

$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

Isso não funciona como esperado porque não sei como incluir o índice na declaração SecondValue. Alguém tem alguma ideia?

    
por TimN_FL 15.10.2017 / 18:05

1 resposta

0

Infelizmente, não há como parametrizar as propriedades do script. Podemos verificar isso lendo a fonte do PowerShell. Internamente, a contabilidade das propriedades do script é armazenada em PSScriptProperty objetos. Quando os valores dessas propriedades são solicitados ou alterados, a função privada InvokeGetter ou InvokeSetter , respectivamente, é chamada. InvokeSetter executa o bloco de script setter com o novo valor como o único argumento (como visto na última linha deste trecho):

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

InvokeGetter executa o getter script block sem nenhum argumento:

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

Portanto, não podemos passar nenhuma informação extra para o getter ou setter. ( scriptThis refere-se apenas a $this , o objeto no qual estamos definindo a propriedade.)

Existe uma solução alternativa: o % cmdletAdd-Type com o parâmetro -TypeDefinition . Você pode incorporar algum código C # (ou VB.NET, se preferir) que defina um tipo indexável :

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;
        }
    }
}
"@

Você pode fazer algo assim:

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

Ou você pode aproveitar o nome do indexador e fazer isso:

$obj.ArrayData(3) = 255 # Note the parentheses, not brackets
Write-Host $obj.ArrayData(3) # Prints the notice, then 255
    
por 19.10.2017 / 01:42

Tags