เพิ่มสมาชิกที่มีค่าอาร์เรย์


2

เนื่องจากปัญหาที่ฉันมีกับคลาส powershell (ไม่มี accessors และ mutators aka getter และ setters) ฉันได้ใช้ Custom Objects ที่สร้างโดยใช้ add-member ฉันมีปัญหาในการหาวิธีที่เหมาะสมในการอ้างอิงค่าอาร์เรย์ใน SecondValue 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รัน setter script block ด้วยค่าใหม่เป็นอาร์กิวเมนต์เท่านั้น (ดังที่เห็นในบรรทัดสุดท้ายของข้อความที่ตัดตอนมานี้):

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>());

ดังนั้นเราไม่สามารถส่งข้อมูลพิเศษใด ๆ ไปยังผู้ทะเยอทะยาน ( 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

ขอบคุณสำหรับคำตอบ. ฉันกลัวว่านี่เป็นกรณี แต่คุณให้หลักฐานสนับสนุนมากกว่าเพียงพอที่จะขจัดข้อสงสัยที่เอ้อระเหย
TimN_FL
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.