Переменные области модуля изменяются без явного назначения

Я совершенно смущен некоторым поведением переменной области видимости, которое я испытываю. Возьмите следующий образец модуля:

$script:intTemplate = 1

[xml]$script:xmlTemplate = @"
<test>
    <element>
    </element>
</test>
"@

function getvar {
    $myint = $script:intTemplate
    $myint++
    Write-output "Myint is $myint while intTemplate is $intTemplate"

    $myxml = $script:xmlTemplate
    $e = $myxml.CreateElement("MyChildElement")
    $myxml.SelectSingleNode("/test").AppendChild($e) |Out-Null
    $myxml.Innerxml.tostring()
    $script:xmltemplate.Innerxml.tostring()
}    

Теперь импорт этого модуля под управлением getvar генерирует:

PS C:\Windows\system32> getvar
Myint is 2 while intTemplate is 1
<test><element></element><MyChildElement /></test>
<test><element></element><MyChildElement /></test>

Дальнейшие запуски getvar продолжают добавлять все больше и больше дочерних элементов в $xmlTemplate, в то время как $intTemplate остается прежним. Я не понимаю, почему $myXml не всегда начинается с простой структуры теста/элемента и, что более важно, как локальная переменная скрипта $xmlTemplate изменяется, а intTemplate - нет.

Любая помощь в выяснении того, что здесь происходит, будет высоко оценена.

Дэйвид


person David F. Severski    schedule 13.11.2012    source источник


Ответы (1)


Насколько я понимаю, область действия не имеет ничего общего с вашей проблемой, когда вы пишете $myInt=$script:intTemplate, вы манипулируете значением, поэтому вы копируете значение. Когда вы пишете $myxml = $script:xmlTemplate, вы манипулируете ссылкой, поэтому копируя ссылку, вы работаете с одним и тем же базовым объектом. Просто попробуйте $script:intTemplate += 1.

person JPBlanc    schedule 14.11.2012
comment
Спасибо за информацию! Итак, некоторые объекты ([XML]) передаются по ссылке, а другие ([INT32]) передаются по значению? Есть ли какая-то документация или способ узнать, как произвольный тип объекта будет передан через операцию присваивания? Я предполагаю, что объекты [string] передаются по значению, но как насчет всех других возможных типов объектов .NET? После того, как вы выпили KoolAid для всего, такое поведение кажется немного произвольным/запутанным. - person David F. Severski; 14.11.2012
comment
@davidski В целом правила для PowerShell такие же, как и для .NET: типы значений передаются по значению, а ссылочные типы по ссылке. Для неизменяемых типов, таких как Int32 и String, разница не очень важна. Однако для изменяемых типов каждое присвоение переменной изменяемого типа значения, например Point создаст независимую копию, а изменяемый ссылочный тип, такой как XmlDocument будут указывать на один и тот же экземпляр объекта. - person Emperor XLII; 19.11.2012