Powershell/.Net: получить ссылку на объект, возвращаемый методом

Я учу себя PowerShell, пишу простой парсер. Я использую класс .Net framework Collections.Stack. Я хочу изменить объект в верхней части стека на месте.

Я знаю, что могу pop() отключить объект, изменить его, а затем push() снова включить, но мне это кажется неэлегантным.

Сначала я попробовал это:

$stk = new-object Collections.Stack
$stk.push( (,'My first value') )
( $stk.peek() ) += ,'| My second value'

Что выдало ошибку:

Assignment failed because [System.Collections.Stack] doesn't contain a settable property 'peek()'.
At C:\Development\StackOverflow\PowerShell-Stacks\test.ps1:3 char:12
+ ( $stk.peek <<<< () ) += ,'| My second value'
    + CategoryInfo          : InvalidOperation: (peek:String) [], RuntimeException
    + FullyQualifiedErrorId : ParameterizedPropertyAssignmentFailed

Далее я попробовал это:

$ary = $stk.peek()
$ary += ,'| My second value'
write-host "Array is: $ary"
write-host "Stack top is: $($stk.peek())"

Что предотвратило ошибку, но все равно не помогло:

Array is: My first value | My second value
Stack top is: My first value

Очевидно, что $ary присваивается копия объекта наверху стека, поэтому, когда я добавляю объект в $ary, объект наверху стека остается неизменным.

Наконец, я прочитал о типе [ref] и попробовал это:

$ary_ref = [ref]$stk.peek()
$ary_ref.value += ,'| My second value'
write-host "Referenced array is: $($ary_ref.value)"
write-host "Stack top is still: $($stk.peek())"

Но до сих пор нет кости:

Referenced array is: My first value | My second value
Stack top is still: My first value

Я предполагаю, что метод peek() возвращает ссылку на фактический объект, а не на клон. Если это так, то ссылка заменяется клоном логикой обработки выражений PowerShell.

Может ли кто-нибудь сказать мне, есть ли способ сделать то, что я хочу сделать? Или мне нужно вернуться к pop()/modify/push()?


person Dan Menes    schedule 22.05.2010    source источник


Ответы (2)


Массив всегда имеет фиксированный размер. Когда вы добавляете элемент в массив, создается новый массив увеличенной длины, а старый массив копируется в новый. Ссылка неявно изменилась, поэтому у вас есть совершенно новый массив с двумя элементами, тогда как стек все еще содержит старый. Вместо этого используйте список.

person Julien Lebosquain    schedule 22.05.2010

Я понял. Копию создавал оператор "+=". Кажется, что вы не можете добавлять элементы в массив .Net. Если я использую объект другого типа, например хэш-таблицу, у меня не возникает проблем с добавлением элементов на место:

$stk.push( @{"1"="My first value"} )
$stk.peek()["2"]="| My second value"
write-host "Stack top keys: $($stk.peek().keys)"
write-host "Stack top values: $($stk.peek().values)"

Который дает

Stack top keys: 1 2
Stack top values: My first value | My second value

Или для объекта, более похожего на массив, работает Collections.ArrayList.

$item = new-object Collections.ArrayList
$stk.push( $item )
$stk.peek().Add( "My first value" )
$stk.peek().Add( "| My second value" )
$obj = $stk.peek()
$obj.Add( "| My third value" )
write-host "Stack top is: $($stk.peek())"

Какие выходы

Stack top is: My first value | My second value | My third value
person Dan Menes    schedule 22.05.2010