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

Я учу себя 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() / изменить / push()?

Ответы [ 2 ]

2 голосов
/ 22 мая 2010

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

1 голос
/ 22 мая 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
...